Three.js mouse picking object

 ̄綄美尐妖づ 提交于 2019-12-18 18:40:04

问题


So i found a lot of tutorials on how to use mouse picking on default objects available in Threejs itself, but is it possible to use mouse picking on imported models like a .obj file and displaying a sphere at the exact position where the user clicks the model? If so, can someone give me a tutorial or at least an example with source code so i can use it. I prefer a tutorial, because thats a better way to learn it. ;)

EDIT: So i got mouse picking working for the model! But now i want to show a little dot at the location where the user clicks the model. I tried to do it the way this demo works: http://mrdoob.github.io/three.js/examples/#canvas_interactive_cubes but can't get it to work, someone who knows why? See code below

// once everything is loaded, we run our Three.js stuff.
var clock = new THREE.Clock();
var stats = initStats();
var particleMaterial;

// create a scene, that will hold all our elements such as objects, cameras and lights.
var PI2 = Math.PI * 2;
particleMaterial = new THREE.SpriteCanvasMaterial( {
    color: 0x000000,
    program: function ( context ) {
        context.beginPath();
        context.arc( 0, 0, 0.5, 0, PI2, true );
        context.fill();
    }
});
var projector = new THREE.Projector();
var scene = new THREE.Scene();

// create a camera, which defines where we're looking at.
var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);


// create a render and set the size
var webGLRenderer = new THREE.WebGLRenderer();
webGLRenderer.setClearColor(new THREE.Color(0xEFEFEF, 1.0));
webGLRenderer.setSize(window.innerWidth, window.innerHeight);
webGLRenderer.shadowMapEnabled = true;

// position and point the camera to the center of the scene
camera.position.x = 0;
camera.position.y = 0;
camera.position.z = 40;
camera.lookAt(new THREE.Vector3(0, 0, 0));


var trackballControls = new THREE.TrackballControls(camera);

trackballControls.rotateSpeed = 3.0;
trackballControls.zoomSpeed = 3.0;
trackballControls.panSpeed = 0.4;
trackballControls.staticMoving = false;

var ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
hemiLight = new THREE.HemisphereLight( 0xFFFFFF, 0xFFFFFF, 0.9 ); 
scene.add(hemiLight);
// add spotlight for the shadows
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(300, 300, 300);
spotLight.intensity = 1;
scene.add(spotLight);

// add the output of the renderer to the html element
$("#WebGL-output").append(webGLRenderer.domElement);

// call the render function
var step = 0;


// setup the control gui
//var controls = new function () {
    // we need the first child, since it's a multimaterial


//}

//var gui = new dat.GUI();
var mesh;
var objects = [];

var loader = new THREE.OBJMTLLoader();
loader.addEventListener('load', function (event) {
    var object = event.content;
    object.traverse( function ( child ) {
        if ( child instanceof THREE.Mesh ) {
            //The child is the bit needed for the raycaster.intersectObject() method
        }
    } );
    object.scale.set(4, 4, 4);
    object.position.set(0, -10, 0);
    object.name = "test";
    scene.add(object);
    objects.push(object);
});

loader.load('models/dancer07.obj', 'models/dancer07.mtl', {side: THREE.DoubleSide});

var plane = new THREE.Mesh(new THREE.PlaneGeometry(400, 400, 50, 50), new THREE.MeshBasicMaterial({ color: 0x808080, wireframe: true }));
plane.rotation.x = -Math.PI / 2;
plane.name = 'Ground';
plane.position.set(0, -10, 0);
scene.add(plane);
objects.push(plane);

render();

function render() {
    stats.update();
    var delta = clock.getDelta();

    if (mesh) {
        //   mesh.rotation.y+=0.006;
    }


    trackballControls.update(delta);

    //webGLRenderer.clear();
    // render using requestAnimationFrame
    requestAnimationFrame(render);
    webGLRenderer.render(scene, camera)
}

function initStats() {

    var stats = new Stats();
    stats.setMode(0); // 0: fps, 1: ms

    // Align top-left
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';

    $("#Stats-output").append(stats.domElement);

    return stats;
}
document.addEventListener('mousedown', onDocumentMouseDown, false);
window.addEventListener( 'resize', onWindowResize, false ); 

function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize( window.innerWidth, window.innerHeight );

    }

function onDocumentMouseDown( event ){
    event.preventDefault();
    var mouseX = (event.clientX / window.innerWidth)*2-1;
    var mouseY = -(event.clientY /window.innerHeight)*2+1;
    var vector = new THREE.Vector3( mouseX, mouseY, 0.5 );
    projector.unprojectVector( vector, camera );
    var raycaster = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
    var intersects = raycaster.intersectObjects( objects, true );
    if (intersects.length > 0) {
        alert("intersect!");
        var particle = new THREE.Sprite( particleMaterial );
        particle.position.copy( intersects[0].point );
        particle.scale.x = particle.scale.y = 300;
        scene.add(particle);    
    }

}

$('#reset').click(function() {
    trackballControls.reset();
});

$('#female').click(function() {
    scene.remove(scene.getObjectByName("test"));
    loader.load('models/dancer07.obj', 'models/dancer07.mtl', {side: THREE.DoubleSide});
});

$('#male').click(function() {
    scene.remove(scene.getObjectByName("test"));
    loader.load('models/doorman.obj', 'models/doorman.mtl', {side: THREE.DoubleSide});
});

回答1:


It doesn't matter if its an imported model or a default object. The mouse picking code in the Three.JS examples works with any sort of mesh.

http://threejs.org/examples/#webgl_interactive_buffergeometry

var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
projector.unprojectVector( vector, camera );

raycaster.set(camera.position, vector.sub(camera.position).normalize());

var intersects = raycaster.intersectObject(mesh); 

Use the meshes created by the loader in the raycaster.intersectObject function. In your case you could get all of the meshes that compose an object with the below loading code.

var loader = new THREE.OBJLoader( manager );
loader.load( 'example.obj', function ( object ) {
    object.traverse( function ( child ) {
        if ( child instanceof THREE.Mesh ) {
            //The child is the bit needed for the raycaster.intersectObject() method
        }
    } );
    object.position.y = - 80;
    scene.add( object );
} );


来源:https://stackoverflow.com/questions/25667394/three-js-mouse-picking-object

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!