7

I'm trying to figure out a way to use a 3D model created with Three.js as a hyperlink. In other words, if I click on a cube (a THREE.CubeGeometry), I want another page to open.

For instance, in this threejs.org example,

how can I change it, so that instead of making little dots on the boxes, clicking on the boxes would open another page, like a hyperlink?

Damjan Pavlica
  • 31,277
  • 10
  • 71
  • 76
lisa
  • 73
  • 1
  • 1
  • 4
  • Hi Lisa and welcome to SO, this can be achieved with the combination of threejs with some custom javascript, but can you please tell that, the redirect link(hyperlink) will be same for every cube(or object) or will it be different – Shiva Jul 11 '14 at 06:05
  • OMG Shiva! Thanks for the quick response! I would like every cube to be a different link. I just found some info on "tquery" so I'm looking into that voraciously... Although I'm not sure whether I'll understand it fully. haha. Thanks again! – lisa Jul 11 '14 at 06:24

3 Answers3

21

One way to achieve it will be to associate custom userData(URL) with every cube while its being created.

So here is a sample code how we can put data in cubes while they are being generated(in jsfiddle similar logic is used between line 25-63)

var object = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({
            color: Math.random() * 0xffffff }));  

object.userData = { URL: "http://stackoverflow.com"};

Now here we use a method called raycasting to detect mouse click, so in principal when the mouse is clicked, we cast a ray(invisible) in the plane perpendicular to the click and we capture all the objects that the ray intersected.

Then we retrieve the first object from the list of intersected objects because that will be near most the screen

ray casting image

To better understand raycasting and object picking refer to this tutorial.

Now while creating the cubes we already inserted the data so we can simply retrieve(URL) it from the intersected cube and redirect the user to that page.

The sample code will be something like this(at line number 95 in the fiddle )

if (intersects.length > 0) {
        window.open(intersects[0].object.userData.URL);
    }

Here us a working jsfille hoping it helps

JSFiddle Link

Shiva
  • 6,677
  • 4
  • 36
  • 61
  • 1
    Shiva! You're a god sent! Thank you sooooooo much! <3! – lisa Jul 11 '14 at 07:28
  • @lisa: Thanks for the comment, if the solution solved your query you can accept the answer(by selecting the green tick mark), or else if you have something else you can ask that too. :) – Shiva Jul 11 '14 at 10:04
  • 1
    @Shiva This is a freaking great answer mate! Thanks for sharing this. – Jean-Michel Provencher Aug 18 '16 at 20:02
  • @Shiva - Hey Shiva, thanks for the great answer! When using this technique `intersects[0]` is an object with multiple attributes, i.e. `distance` of the intersection, which face was intersected, etc. However, this is only for the entry point of the ray inside the intersected object. Is there a way to get all the info for the location where the ray **exited** the object? – Matteo Aug 31 '16 at 19:23
  • @Shiva - In other words, how can I get a list of all the intersections of an object with a certain ray? – Matteo Aug 31 '16 at 19:24
  • @Shiva - I found the answer [here](http://threejs.org/docs/api/core/Raycaster.html) in case you're interested: `for meshes, faces must be pointed towards the origin of the ray in order to be detected; intersections of the ray passing through the back of a face will not be detected. To raycast against both faces of an object, you'll want to set the material's side property to THREE.DoubleSide`. – Matteo Sep 01 '16 at 17:03
  • Thanks for the example, one question how I open the link on the same window? – hanan-mstudio Apr 24 '19 at 14:14
0

In this case, 3Dink.js is useful. It is a wrapper library of three.js for WebGL that is enabled to make 3D hyperlinks easily.

In the shortest case, It can realize click and light emission in 3 lines.

DDDINK.addURL(object, "https://www.npmjs.com/package/3dink");
DDDINK.readRendererObj( renderer, scene, camera );
DDDINK.domEvent.addFnc();

Please browse it's repository. https://github.com/takashift/3Dink.js

-1

You can do it by modifying this function:

function onDocumentMouseDown( event ) {

    // ......

    if ( intersects.length > 0 ) {

        switch(intersects[0].object) {
            case google_object:
                window.open('http://google.com');
                break;
            case yahoo_object:
                window.open('http://yahoo.com');
                break;
        } 

    }

    // ......
}
parchment
  • 4,063
  • 1
  • 19
  • 30
  • hmm, so I tried this and it doesn't seem to work. I'm sure I'm somehow not implementing this correctly... – lisa Jul 11 '14 at 07:08
  • Well, since you mentioned tquery, they have an example that looks like just what you want. http://jeromeetienne.github.io/tquery/plugins/linkify/examples/ – parchment Jul 11 '14 at 07:10
  • yeah, I'll try it out with tquery! I was just thinking that there was probably a really easy solution that I am blind to. Thanks again! – lisa Jul 11 '14 at 07:13