3

I am trying to detect a cube click in an Object3D group of Cubes. I have viewed, and tried to incorporate the examples and tutorials found at:

http://mrdoob.github.com/three.js/examples/webgl_interactive_cubes.html

and

http://mrdoob.github.com/three.js/examples/canvas_interactive_cubes.html

Also, I have consulted the posts on this site at:

Three.js - how to detect what shape was selected? after drag

and

how to Get CLICKED element in THREE.js

But for some reason, it's still not working. Can anyone please tell me what I'm doing wrong? Here is my code, thanks:

<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Double Stamp It No Erasies</title>
<style>
html {
    background: url(Images/ComicBookExplosionBackground.jpg) no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
}
body {
}
</style>
<script src="ThreeJs/build/three.min.js"></script>       
</head>

<body onLoad="onLoad();" style="">
<div id="container" style="width:100%; height:100%; position:absolute;"></div>
<script>
            var container, ButtonsCamera, ButtonsScene, ButtonsRenderer, ButtonsGeometry, ButtonsGroup;
            var mouseX = 0, mouseY = 0;
            var windowHalfX = window.innerWidth / 2;
            var windowHalfY = window.innerHeight / 2;   
            /****************************** CLICK START **********************************/
var mouse = { x: 0, y: 0 }, projector, INTERSECTED;
var objects = [];
    /****************************** CLICK END **********************************/


            document.addEventListener( 'mousemove', onDocumentMouseMove, false );
            //document.addEventListener( 'mousedown', onDocumentMouseDown, false );
            init();
            animate();      

            function init() {
                container = document.createElement( 'div' );
                document.body.appendChild( container );         
                ButtonsCamera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 1, 10000 );
                ButtonsCamera.position.z = 500;
                ButtonsScene = new THREE.Scene();
                ButtonsScene.fog = new THREE.Fog( 0xffffff, 1, 10000 );
                /*************************** STACKOVERFLOW 1ST ANSWER START **********************************/ 
        var ButtonsGeometry = new THREE.CubeGeometry( 100, 100, 100 );
var ButtonsMaterial = new THREE.MeshFaceMaterial( [
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } ),
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } ),
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } ),
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } ),
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } ),
    new THREE.MeshBasicMaterial( { map: THREE.ImageUtils.loadTexture( 'Images/Twitter.jpg' ) } )] );        
                /*************************** STACKOVERFLOW 1ST ANSWER END **********************************/   
                ButtonsGroup = new THREE.Object3D();
                for ( var i = 0; i < 100; i ++ ) {
                    var ButtonsMesh;
                    if(i == 0)
                    {
                    ButtonsMesh = new THREE.Mesh( ButtonsGeometry, ButtonsMaterial );
                    }
                    else
                    {
                    ButtonsMesh = new THREE.Mesh( ButtonsGeometry, ButtonsMaterial );
                    }
                    ButtonsMesh.position.x = Math.random() * 2000 - 1000;
                    ButtonsMesh.position.y = Math.random() * 2000 - 1000;
                    ButtonsMesh.position.z = Math.random() * 2000 - 1000;
                    ButtonsMesh.rotation.x = Math.random() * 360 * ( Math.PI / 180 );
                    ButtonsMesh.rotation.y = Math.random() * 360 * ( Math.PI / 180 );
                    ButtonsMesh.matrixAutoUpdate = false;
                    ButtonsMesh.updateMatrix();
                    ButtonsGroup.add( ButtonsMesh );
                }
                ButtonsScene.add( ButtonsGroup );

            /****************************** CLICK START **********************************/
            objects.push( ButtonsMesh );
projector = new THREE.Projector();  
/****************************** CLICK END **********************************/



                ButtonsRenderer = new THREE.WebGLRenderer();
                ButtonsRenderer.setSize( window.innerWidth, window.innerHeight );
                ButtonsRenderer.sortObjects = false;
                container.appendChild( ButtonsRenderer.domElement );
            window.addEventListener( 'resize', onWindowResize, false );
            /****************************** CLICK START **********************************/
document.addEventListener( 'mousedown', onDocumentMouseDown, false );
/****************************** CLICK END **********************************/


            }

            /****************************** CLICK START **********************************/
function onDocumentMouseDown( event ) {
//alert('clicky');
                event.preventDefault();

                var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
                projector.unprojectVector( vector, ButtonsCamera );

                var raycaster = new THREE.Raycaster( ButtonsCamera.position, vector.subSelf( ButtonsCamera.position ).normalize() );

                var intersects = raycaster.intersectObjects( objects);

                if ( intersects.length > 0 ) {
                    intersects[ 0 ].object.material.color.setHex( Math.random() * 0xffffff );

                    var particle = new THREE.Particle( particleMaterial );
                    particle.position = intersects[ 0 ].point;
                    particle.scale.x = particle.scale.y = 8;
                    ButtonsScene.add( particle );

                }

                /*
                // Parse all the faces
                for ( var i in intersects ) {

                    intersects[ i ].face.material[ 0 ].color.setHex( Math.random() * 0xffffff | 0x80000000 );

                }
                */
            }
/****************************** CLICK END **********************************/




            function onWindowResize() {
                windowHalfX = window.innerWidth / 2;
                windowHalfY = window.innerHeight / 2;
                ButtonsCamera.aspect = window.innerWidth / window.innerHeight;
                ButtonsCamera.updateProjectionMatrix();
                ButtonsRenderer.setSize( window.innerWidth, window.innerHeight );
            }




            function onDocumentMouseMove(event) {
                mouseX = ( event.clientX - windowHalfX ) * 10;
                mouseY = ( event.clientY - windowHalfY ) * 10;
            }

            function animate() {                
                requestAnimationFrame( animate );
                render();
                ButtonsStats.update();
            }


            /****************************** CLICK START **********************************/
var radius = 100;
            var theta = 0;
            /****************************** CLICK END **********************************/


            function render() {




                var ButtonsTime = Date.now() * 0.001;
                var rx = Math.sin( ButtonsTime * 0.7 ) * 0.5,
                    ry = Math.sin( ButtonsTime * 0.3 ) * 0.5,
                    rz = Math.sin( ButtonsTime * 0.2 ) * 0.5;
                ButtonsCamera.position.x += ( mouseX - ButtonsCamera.position.x ) * .05;
                ButtonsCamera.position.y += ( - mouseY - ButtonsCamera.position.y ) * .05;
                ButtonsCamera.lookAt( ButtonsScene.position );
                ButtonsGroup.rotation.x = rx;
                ButtonsGroup.rotation.y = ry;
                ButtonsGroup.rotation.z = rz;
                ButtonsRenderer.render( ButtonsScene, ButtonsCamera );
            }
        </script>

</body>
</html>
Community
  • 1
  • 1
  • Could you setup a [jsfiddle](http://jsfiddle.net/)? – mrdoob Jan 04 '13 at 12:44
  • Hello mrdoob, thanks for all the help you are giving and the super quick response to my question is awesome. I have set up a jsfiddle as you requested, and here is the share link: http://jsfiddle.net/sweetj77/7BymE/1/ – Jonathan Mattox Jan 04 '13 at 16:44
  • You need to learn how to set up a jsfiddle so it runs (with the current version of the library). Example: http://jsfiddle.net/rgE2j/4/ – WestLangley Jan 04 '13 at 17:26
  • Hello, I have setup the jsfiddle per the example you sent. I searched the jsfiddle documentation for how to upload attachments, but I did not find one. The cubes I need to detect a click on have an image mapped to all sides. Please advise. Thanks, Jonathan Here is my site if you want to look at it in production: http://www.doublestampitnoerasies.com/ – Jonathan Mattox Jan 05 '13 at 01:13

1 Answers1

4

Hey I hope I am not too late but anyway the solution to your problem is a misplaced statement and a deprecated method.

You only have one object in your objects array that is why when you click on a random box the raycaster is unlikely to detect an intersection. Move the array push call into the for loop in order to add every object into the array instead of the last object created.

for (var i = 0; i < 100; i++) {
    var ButtonsMesh;
    if (i == 0) 
    {
        ButtonsMesh = new THREE.Mesh(ButtonsGeometry, ButtonsMaterial);
    } 
    else 
    {
        ButtonsMesh = new THREE.Mesh(ButtonsGeometry, ButtonsMaterial);
    }
    ButtonsMesh.position.x = Math.random() * 2000 - 1000;
    ButtonsMesh.position.y = Math.random() * 2000 - 1000;
    ButtonsMesh.position.z = Math.random() * 2000 - 1000;
    ButtonsMesh.rotation.x = Math.random() * 360 * (Math.PI / 180);
    ButtonsMesh.rotation.y = Math.random() * 360 * (Math.PI / 180);
    ButtonsMesh.matrixAutoUpdate = false;
    ButtonsMesh.updateMatrix();
    ButtonsGroup.add(ButtonsMesh);
    objects.push(ButtonsMesh);
}

The second problem is that newer versions of THREE don't use subSelf(), it is replaced by sub(). So make the change to the Raycaster definition.

var raycaster = new THREE.Raycaster(ButtonsCamera.position, 
                vector.sub(ButtonsCamera.position).normalize());

That should solve your problems but there are more errors in your code but they are all trivial.

I hope this helps and here is a working version: http://jsbin.com/uhihoq/1/edit

Peace!

mand
  • 292
  • 1
  • 11
  • Hi, this answer is was informational, but I had a few questions I ran into when trying to alter the example. I tried changing the CubeGeometry to SphereGeometry, It all renders and everything but the hit tests a little off. I have been searching for good up to date resources and tutorials on three js for about two months and havent found any using the latest. Any ideas would be appreciated. Thanks – dotfury Jul 02 '13 at 03:35
  • Yeah the hits are a bit inaccurate and I have been trying to find a solution for a while now. What I do know is that the problem has to do with how the browser mouse positions are transformed into three coordinates, the window dimensions and the camera position. The Raycaster object has a precision property you can play around with though. I'm working on some Three tutorials, using the latest version, I will send you a link when I am done. – mand Jul 28 '13 at 09:03