JavaScript Double Click Function Three.js

时间:2016-04-15 11:08:27

标签: javascript function canvas three.js

I've got a double click function to allow the user to double click on a car model and it displays which objects have been intersected; e.g. wipers, grille, tyres and so on, and this function displays them in a list with the number of items the double click intersected with.

However, I am now trying to get it so that when a certain part of the car is clicked, for example, the tyres, it will display a paragraph with information on them. I can see how this is just a case of checking the name of the intersecting object and then displaying the relevant text if it intersects it, but every time I go to do what I think is right, it just breaks the already existing function to the point where the whole thing won't run.

I'm not exactly a JavaScript or Three.js pro at all, but trying to progress my function further is proving to be rather difficult.

Any suggestions? I've included the entire double click function, however it's when it's checking if there has been intersections near the bottom that is where the alterations need to be.

// On Mouse double click event function
function onDoubleClick(event) {
// Set the mouse down flag to false
mouseDown = false;

// Canvas x (left) and y (top) position
var canvasLeft = 0;
var canvasTop = 0;

// "event.clientX" is the mouse x position. "event.clientY" is the mouse y position
var tempX = event.clientX - canvasLeft;
var tempY = event.clientY - canvasTop;
// Create a normalised vector in 2d space
var vector = new THREE.Vector3((tempX / window.innerWidth) * 2 - 1, - (tempY / innerHeight) * 2 + 1, 0.5);

// Unproject a 2D point into the 3D word
// Use the camera projection matrix to transform the vector to the 3D world space
vector.unproject(camera);

// Send a ray in the direction the user has clicked from the cameras position
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());

// Check if the ray has intersected with any objects and get intersections
var intersects = raycaster.intersectObjects(objects, true);

// Check if intersected with objects
if (intersects.length > 0) {
    var tempStr = "Number of items: " + intersects.length + " ";
    // List the items that were hit
    for(var i=0; i < intersects.length; i++){
        if(intersects[i].object.name != ""){
            // The mesh name set above
            tempStr += " | Name: " + intersects[i].object.name;
        } else {
            // The names inside the model
            tempStr += " | Name: " + intersects[i].object.parent.name;
        }
    }

    //Debug information
    document.getElementById("debugInfo").innerHTML = tempStr + ".<br>";
    //END
}

}

EDIT: This is the entire code for the javascript file, as altering elements of the double click function seems to stop the page from loading.

    window.onload = init;

// declare variables    
var scene,camera,renderer, container;
var controls, guiControls, datGUI;
var grid, color;
var cube, cubeGeometry, cubeMaterial; 
var plane, planeGeometry, planeMaterial;
var skyBoxMesh, texture_placeholder;
var spotLight;
var stats;

// Handles the mouse events.
var mouseOverCanvas;
var mouseDown;
// An array of objects that can be clicked on
var objects = [];

//DAE models
var showroom ,carOld, carNew;

var daeObject;

var animations;
var kfAnimations = [];
var kfAnimationsLength = 0;
var lastFrameCurrentTime = [];

var clock = new THREE.Clock();

var mouseOverCanvas, mouseDown;
var objectsClick=[];

function init() {
    container = document.createElement( 'div' );
    document.body.appendChild( container );

    //creates empty scene
    scene = new THREE.Scene();

    //camera
    camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, .1, 500);
    camera.position.x = 40;
    camera.position.y = 40;
    camera.position.z = 40;
    camera.lookAt(scene.position);

    //renderer
    renderer = new THREE.WebGLRenderer({antialias:true});
    renderer.setClearColor(0xe6f2ff);
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;
    renderer.shadowMapSoft = true;
    container.appendChild( renderer.domElement );

    // Add an event to set if the mouse is over our canvas
    renderer.domElement.onmouseover=function(e){ mouseOverCanvas = true; }
    renderer.domElement.onmousemove=function(e){ mouseOverCanvas = true; }
    renderer.domElement.onmouseout=function(e){ mouseOverCanvas = false; }

    renderer.domElement.onmousedown=function(e){ mouseDown = true; }
    renderer.domElement.onmouseup=function(e){ mouseDown = false; }

    // Double Click Event. Set a function called "onDoubleClick"
    renderer.domElement.ondblclick=onDoubleClick;

     // stats
    stats = new Stats();
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    container.appendChild( stats.domElement );

     //adds controls
     controls = new THREE.OrbitControls(camera, renderer.domElement);
     controls.addEventListener('change', render);

     var ambient = new THREE.AmbientLight( 0xadad85 );
     scene.add( ambient ); 

     //---------- creates grid ---------------
     grid = new THREE.GridHelper(50,5);
     color= new THREE.Color("rgb(255,0,0)");
     grid.setColors( 0x000000);
     scene.add(grid);

     //----------- creates cube --------------
     cubeGeometry = new THREE.BoxGeometry(5,5,5);
     cubeMaterial = new THREE.MeshPhongMaterial({color: 0xff3300});
     cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
     cube.position.x = 0;
     cube.position.y = 6;
     cube.position.z = 2.5;
     cube.castShadow = true;

     scene.add(cube);

     //----------- creates plane ---------------
     planeGeomenty= new THREE.PlaneGeometry(100,100,100);
     planeMaterial = new THREE.MeshLambertMaterial({color: 0x00cc00});
     plane = new THREE.Mesh(planeGeomenty, planeMaterial);
     //position the add objects to the scene
     plane.rotation.x = -.5*Math.PI;
     plane.receiveShadow = true;
     scene.add(plane);

    //------------- skyBox --------------
    texture_placeholder = document.createElement('canvas');
    texture_placeholder.width = 128;
    texture_placeholder.height = 128;

    var context = texture_placeholder.getContext('2d');
    context.fillStyle = 'rgb(200,200, 200)';
    context.fillRect(0, 0,texture_placeholder.width, texture_placeholder.height);

    var materials = [
         loadTexture('images/skybox/posX.jpg'),
         loadTexture('images/skybox/negX.jpg'),
         loadTexture('images/skybox/posY.jpg'),
         loadTexture('images/skybox/negY.jpg'),
         loadTexture('images/skybox/posZ.jpg'),
         loadTexture('images/skybox/negZ.jpg')
         ];
    skyBoxMesh = new THREE.Mesh(new THREE.BoxGeometry(500,500,500,7,7,7),
                                new THREE.MeshFaceMaterial(materials));
    skyBoxMesh.scale.x = -1;
    scene.add(skyBoxMesh);

    //---------- loads collada files  -----------
    loadCollada();

    daeObject = cube; 
    // initialise datGUI controls values
    guiControls = new function() {
        this.rotationY = 0.0;

        this.positionX = 0.0;
        this.positionY = 0.0;
        this.positionZ = -10;

        this.lightX = 20;
        this.lightY = 35;
        this.lightZ = 40;

        this.intensity = 1;
        this.distance = 0;
        this.angle = 1.570;
        this.target = cube;
    }

    //add spotLight with starting parameters
    spotLight = new THREE.SpotLight(0xffffff);
    spotLight.castShadow = true;
    spotLight.position.set(20,35,40);
    spotLight.intensity = guiControls.intensity;
    spotLight.distance = guiControls.distance;
    spotLight.angle = guiControls.angle;
    scene.add(spotLight);

    //adds controls on the scene
    datGUI = new dat.GUI();
   // datGUI.add(guiControls, 'positionZ', 0, 1);
    datGUI.add(guiControls, 'positionZ', -10, 25, 0.5). name("Move the car");
    datGUI.add(guiControls, 'rotationY', 0, 1).name('Rotate the car');

    datGUI.add(guiControls, 'lightX', -60, 180);
    datGUI.add(guiControls, 'lightY', 0, 180);
    datGUI.add(guiControls, 'lightZ', -60, 180);

    datGUI.add(guiControls, 'target',[ 'cube','Modern Mini', 'Classic Mini']).onChange(function() {
        if(guiControls.target == 'cube'){
            spotLight.target = cube;
            daeObject = cube;
        } 
         else if(guiControls.target == 'Classic Mini'){
            spotLight.target = carOld;
            daeObject = carOld;
        }
        else if(guiControls.target = 'Modern Mini'){
            spotLight.target = carNew;
            daeObject = carNew;
        }           
    });

    datGUI.add(guiControls, 'intensity', 0.01, 5).onChange(function (value){
        spotLight.intensity = value;
    });
    datGUI.add(guiControls, 'distance', 0, 1000).onChange(function (value){
        spotLight.distance = value;
    });
    datGUI.add(guiControls, 'angle', 0.001, 1.570).onChange(function (value){
        spotLight.angle = value;
    });

    datGUI.close();
    container.appendChild(renderer.domElement);

    window.addEventListener( 'resize', onWindowResize, false );
}     
//------------------------- END INIT() ----------------------------

function onWindowResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( window.innerWidth, window.innerHeight );

}

function loadCollada() {
    //--- Loads the Classic Mini ---
    colladaLoader = new THREE.ColladaLoader();
    colladaLoader.options.convertUpAxis = true;
    colladaLoader.load( 'dae_files/ClassicMini.dae', function ( collada ) {
        carOld = collada.scene; // stores dae file to a global variable

        carOld.position.set( 14.5, 1.8, -10 );         
        carOld.scale.set( 0.04, 0.04, 0.04 );           

        carOld.traverse(function (child) {
            child.castShadow = true;
            child.receiveShadow = true;
           });

        carOld.updateMatrix();
        carOld.name = "Classic";
        scene.add( carOld );
        objects.push( carOld );
    } );

    //--- loads Modern Mini ---
    colladaLoader = new THREE.ColladaLoader();
    colladaLoader.options.convertUpAxis = true;
    colladaLoader.load( 'dae_files/ModernMini.dae', function ( collada ) {
        carNew = collada.scene;

        carNew.position.set( -14.5, 6.3, -10 ); 
        carNew.scale.set( 0.06, 0.06, 0.06 );   

        // creates shadow   
        carNew.traverse(function (child) {
        child.castShadow = true;
        child.receiveShadow = true;
        });

        carNew.updateMatrix();
        carNew.name = "Modern";
        scene.add( carNew );
        objects.push( carNew );
    } );

    //--- loads the Showroom ---    
    colladaLoader = new THREE.ColladaLoader();
    colladaLoader.options.convertUpAxis = true; 
    colladaLoader.load( 'dae_files/roomAnim2.dae', function  collada( collada ) {
        showroom = collada.scene;
        animations = collada.animations;

        kfAnimationsLength = animations.length;
        // Initialise last frame current time.
        for ( var i = 0; i < kfAnimationsLength; i++ ) {
            lastFrameCurrentTime[i] = 0;
        }
        // Get all the key frame animations.
        for ( var i = 0; i < kfAnimationsLength; i++ ) {
            var anim = animations[ i ];
            var keyFrameAnim = new THREE.KeyFrameAnimation( anim );
            keyFrameAnim.timeScale = 1;
            keyFrameAnim.loop = false;
            kfAnimations.push( keyFrameAnim );

            anim = kfAnimations[i];
            anim.play();
        }

        showroom.position.set(0, 0, -20);
        showroom.scale.set(0.06, 0.06, 0.06);

        showroom.traverse(function (child) {
            child.castShadow = true;
            child.receiveShadow = true;
           });

        showroom.updateMatrix();
        scene.add( showroom );
        animate();
    } );    
}

// On Mouse double click event function
function onDoubleClick(event) {
    // Set the mouse down flag to false
    mouseDown = false;

    // Canvas x (left) and y (top) position
    var canvasLeft = 0;
    var canvasTop = 0;

    // "event.clientX" is the mouse x position. "event.clientY" is the mouse y position
    var tempX = event.clientX - canvasLeft;
    var tempY = event.clientY - canvasTop;
    // Create a normalised vector in 2d space
    var vector = new THREE.Vector3((tempX / window.innerWidth) * 2 - 1, - (tempY / innerHeight) * 2 + 1, 0.5);

    // Unproject a 2D point into the 3D word
    // Use the camera projection matrix to transform the vector to the 3D world space
    vector.unproject(camera);

    // Send a ray in the direction the user has clicked from the cameras position
    var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());

    // Check if the ray has intersected with any objects and get intersections
    var intersects = raycaster.intersectObjects(objects, true);

    // Check if intersected with objects
    if (intersects.length > 0) {
        var tempStr = "Number of items: " + intersects.length + " ";
        // List the items that were hit
        for(var i=0; i < intersects.length; i++){
            if(intersects[i].object.name != ""){
                // The mesh name set above
                tempStr += " | Name: " + intersects[i].object.name;
            } else {
                // The names inside the model
                tempStr += " | Name: " + intersects[i].object.parent.name;
            }
        }

        //Debug information
        document.getElementById("debugInfo").innerHTML = tempStr + ".<br>";
        //END
    }
}

function loopAnimations(){
    // Loop through all animations
    for ( var i = 0; i < kfAnimationsLength; i++ ) {
        // Check if the animation is player and not paused.
        if(kfAnimations[i].isPlaying && !kfAnimations[i].isPaused){
            if(kfAnimations[i].currentTime == lastFrameCurrentTime[i]) {
                kfAnimations[i].stop();
                //kfAnimations[i].play();
                lastFrameCurrentTime[i] = 0;
            }
        }
    }
}

function play_pauseAnim() {
    //checks is there animation and is it paused    
    if(kfAnimationsLength > 0) {
        if(kfAnimations[0].isPlaying) {
            for(i = 0; i < kfAnimationsLength; i++){
                kfAnimations[i].stop();
            }
        }else {
            for(i = 0; i < kfAnimationsLength; i++) {
                lastFrameCurrentTime[i] = 0;
                //kfAnimations[i].play(kfAnimations[i].currentTime);
                kfAnimations[i].play(0);
            }
        }
    }   
}

function checkTime(){
    if(kfAnimationsLength > 0) {
        if(kfAnimations[0].isPlaying) {
            if(kfAnimations[0].currentTime > 3){
                play_pauseAnim();
            }
        }
    }
}

// create a render loop to draw the scene 60 times per second
function render() {
    //checkTime();

    daeObject.rotation.y += guiControls.rotationY;

    //if (daeObject.position.z < 25) {
    daeObject.position.z = guiControls.positionZ;   
    //}

    spotLight.rotation.x += guiControls.rotationX;
    spotLight.rotation.y += guiControls.rotationY;
    spotLight.rotation.z += guiControls.rotationZ;

    stats.update(); 
}

function animate () {
    var deltaTime = clock.getDelta();
    for ( var i = 0; i < kfAnimationsLength; i++ ) {
        // Get a key frame animation.
        var anim = kfAnimations[i];
        anim.update( deltaTime );
    }
    loopAnimations();
    requestAnimationFrame(animate);
        // Update last frame current time.
    for ( var i = 0; i < kfAnimationsLength; i++ ) {
        lastFrameCurrentTime[i] = kfAnimations[i].currentTime;
    }
    render();   
    renderer.render(scene, camera);
}

// Loads skybox texture
function loadTexture(path) {
    var texture = new THREE.Texture(texture_placeholder);
    var material = new THREE.MeshBasicMaterial({
                map: texture,
                overdraw: 0.5
    });
    var image = new Image();
    image.onload = function() {
        texture.image = this;
        texture.needsUpdate = true;
    };
    image.src = path;
    return material;    
}

1 个答案:

答案 0 :(得分:1)

Macast,

请检查您是否忘记了代码:

var objets = [];
var raycaster = new THREE.Raycaster();

对于汽车的每一部分这一行:

objects.push( mesh );

例如:

var geometry = new THREE.RingGeometry( 1, 5, 32 );
var material = new THREE.MeshBasicMaterial( { color: 0xff0000, side: THREE.DoubleSide } );
var simpleTire = new THREE.Mesh( geometry, material );
simpleTire.name = 'tire';
objects.push( simpleTire );
scene.add( simpleTire );

然后,这很简单:

if ( intersects.length > 0 ) {
    switch(intersects[0].object.name){
        case 'tire':
            console.log('A pretty red tire');
        break;
        case 'motor':
            console.log('An electric motor');
        break;
       }
 }