ThreeJS - how to pick just one type of objects?

2019-01-12 11:39发布

I'm new to ThreeJS and I have an issue with picking objects by raycasting. I have created some spheres and some lines but only want to change the spheres on mouseover. I think I need to add some condition in the raycast code but I have no idea what...

Here's my code, hope anyone can help:

This creates the objects:

var numSpheres = 10;
var angRand = [numSpheres];
var spread = 10;
var radius = windowY/5;
var radiusControl = 20;

//sphere
var sphereGeometry = new THREE.SphereGeometry(0.35, 100, 100);

//line
var lineGeometry = new THREE.Geometry();
var lineMaterial = new THREE.LineBasicMaterial({
    color: 0xCCCCCC
});

//create dynamically
for (var i = 0; i < numSpheres; i++) {

    var sphereMaterial = new THREE.MeshBasicMaterial({color: 0x334455});
    var sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);

    var line = new THREE.Line(lineGeometry, lineMaterial);

    angRand[i] = Math.floor((Math.random() * 360) + 1);//random angle for each sphere/line
    var radiusIncr = spread * (angRand[i]+200)/180;
    var xPos = Math.cos((360/numSpheres * (i) + angRand[i]/2 )) * (radius - radiusIncr);
    var yPos = Math.sin((360/numSpheres * (i) + angRand[i]/2 )) * (radius - radiusIncr);
    var offsetY = Math.floor((Math.random()*5)+1);

    sphere.position.x = xPos/radiusControl;
    sphere.position.y = yPos/radiusControl + offsetY; 

    lineGeometry.vertices.push(
        new THREE.Vector3(0, 0, 0),
        new THREE.Vector3(sphere.position.x, sphere.position.y, 0)
    );

    scene.add(sphere);
    scene.add(line);
}

And this is my raycast:

var mouse = {
        x: 0,
        y: 0
    },
    INTERSECTED;

window.addEventListener('mousemove', onMouseMove, false);
window.requestAnimationFrame(render);

function onMouseMove(event) {
    // calculate mouse position in normalized device coordinates 
    // (-1 to +1) for both components 
    //event.preventDefault();
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    //console.log(mouse.x + " | " + mouse.y);
}

function mousePos() {
    // find intersections

    // create a Ray with origin at the mouse position
    //   and direction into the scene (camera direction)
    var vector = new THREE.Vector3(mouse.x, mouse.y, 0.5);
    vector.unproject(camera);

    var ray = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
    ray.linePrecision = 1;

    // create an array containing all objects in the scene with which the ray intersects
    var intersects = ray.intersectObjects(scene.children, true);

    //console.log(intersects.length);

    // INTERSECTED = the object in the scene currently closest to the camera 
    //      and intersected by the Ray projected from the mouse position    

    // if there is one (or more) intersections
    if (intersects.length > 0) {
        // if the closest object intersected is not the currently stored intersection object
        if (intersects[0].object != INTERSECTED) {
            // restore previous intersection object (if it exists) to its original color
            if (INTERSECTED)
                INTERSECTED.material.color.setHex(INTERSECTED.currentHex);

            // store reference to closest object as current intersection object
            INTERSECTED = intersects[0].object;
            // store color of closest object (for later restoration)
            INTERSECTED.currentHex = INTERSECTED.material.color.getHex();
            // set a new color for closest object
            INTERSECTED.material.color.setHex(0xEE7F00);
            //INTERSECTED.radius.set( 1, 2, 2 );
        }
    } else // there are no intersections
    {
        // restore previous intersection object (if it exists) to its original color
        if (INTERSECTED)
            INTERSECTED.material.color.setHex(INTERSECTED.currentHex);
        //INTERSECTED.scale.set( 1, 1, 1 );
        // remove previous intersection object reference
        //     by setting current intersection object to "nothing"
        INTERSECTED = null;
    }
}

4条回答
Root(大扎)
2楼-- · 2019-01-12 12:20

1.use different arrays to place different objects
a.for all objectType1,after scene.add(objectType1)-> do array1.push(objectType1)
b.for all objectType 2,after scene.add(objectType2)-> do array2.push(objectType2)

now whichever type of objects you want to interact, pass that array in intersect as-
var intersects = raycaster.intersectObjects( arrayType1,true);

now only the arrayType1 objects will interact.

查看更多
Explosion°爆炸
3楼-- · 2019-01-12 12:21

The raycast returns an intersect array of objects which itself contains information about what the ray hit.

Since you only have spheres and lines you can branch on the geometry type intersects[0].object.geometry.type which would be either 'LineGeometry' or 'SphereGeometry'.

Edit: Obligatory jsfiddle, see console for hit output. http://jsfiddle.net/z43hjqm9/1/

查看更多
ら.Afraid
4楼-- · 2019-01-12 12:37

To simplify working with the mouse, you can use the class EventsControls. Try to make through this example.

<script src="js/controls/EventsControls.js"></script>

EventsControls = new EventsControls( camera, renderer.domElement );

EventsControls.attachEvent('mouseOver', function() {

    this.container.style.cursor = 'pointer';
    this.mouseOvered.material = selMaterial;
    ... 

});

EventsControls.attachEvent('mouseOut', function() {

    this.container.style.cursor = 'auto';
    this.mouseOvered.material = autoMaterial;
    ...

});

    //

    function render() {
           EventsControls.update();
           controls.update();
           renderer.render(scene, camera);
    }
查看更多
劫难
5楼-- · 2019-01-12 12:37

In your code,

var intersects = ray.intersectObjects(scene.children, true);

the first parameter to the call is an object that will be evaluated to see if it, or any of its descendants (recursive is true) intersect the ray.

So, simply create an object target and add the spheres to it (but not the lines).

This will make your call also more effective

查看更多
登录 后发表回答