通过拖动检测对象碰撞。尝试使用raycaster intersectObjects方法

时间:2018-11-30 00:08:11

标签: three.js

我只是在尝试检测下部球体(可拖动的球体)何时与上部球体相交。我敢肯定,有些事情我不理解,不幸的是,什么都没让我想到。

<script src='https://threejs.org/build/three.min.js'></script>
<script src='https://threejs.org/examples/js/controls/DragControls.js'></script>
<script>
window.onload = init;
// Global variables
var renderer, raycaster, mouse, 
scene, camera, sphere1, sphere2, 
sphere3, sphere4;

raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();

function init(){
    // Get WebGL ready
    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    renderer = this.renderer;
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
    camera.position.set(0, 0, 100);
    camera.lookAt(0, 0, 0);
    scene = new THREE.Scene();
    // Get set                
    drawSpheres();
    // Go
    eventful();
    animate();
};

function animate(){
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
};

function eventful(){ // Where all events happen
    new THREE.DragControls([sphere1], camera, renderer.domElement);
    window.addEventListener( 'mousemove', onMouseMove, false);   
};

function drawSphere(){ // Sphere geometry
    var geometry, material, sphere;
    geometry = new THREE.SphereBufferGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
    material = new THREE.MeshNormalMaterial();
    sphere = new THREE.Mesh(geometry, material);
    return sphere;
};

function drawSpheres(){ // Draw four corners for the quadrant
    sphere1 = drawSphere(); sphere1.position.set(20, 0, 0);
    sphere2 = drawSphere(); sphere2.position.set(15, 23, 0);
    sphere3 = drawSphere(); sphere3.position.set(0, 22, 0);
    sphere4 = drawSphere(); sphere4.position.set(-20, 20, 0);
    scene.add(sphere1, sphere2, sphere3, sphere4);
};

function onMouseMove(event){ // Calculate mouse movements
    // Pixel coordinates
    mouse.x = event.clientX;
    mouse.y = event.clientY;
    raycasting(renderer, scene, camera);    
};

function raycasting(renderer, scene, camera){
    raycaster.setFromCamera(sphere1, camera); // Update the picking ray with the camera and mouse movements
    intersects = raycaster.intersectObjects([sphere2, sphere3, sphere4]);
    for(var i = 0; i < intersects.length; i++){
        intersects[i].object.material.color.set(0xff0000);
        console.log('Hit on: ', intersects[i]);
    }
};
</script>

我唯一能想到的是我对intersectObjects()方法或setFromCamera()的用法,但我不确定。我认为这是有道理的,因为它是在鼠标移动时更新的。我怎么说:“当我移动球体并检测到碰撞时,我希望可拖动球体成为射线投射器”?或者更简单的方法来检测何时发生碰撞。

例如,考虑以下内容:

window.onload = init;
// Global variables
var renderer, raycaster, mouse, 
scene, camera, sphere1, sphere2, 
sphere3, sphere4;

raycaster = new THREE.Raycaster();
mouse = new THREE.Vector2();
console.log(raycaster);

function init(){
    // Get WebGL ready
    renderer = new THREE.WebGLRenderer({antialias: true});
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    renderer = this.renderer;
    camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
    camera.position.set(0, 0, 100);
    camera.lookAt(0, 0, 0);
    scene = new THREE.Scene();
    // Get set                
    drawSpheres();
    // Go
    eventful();
    animate();
};

function animate(){
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
};

function eventful(){ // Where all events happen
    new THREE.DragControls([sphere1], camera, renderer.domElement);
    window.addEventListener( 'mousemove', onMouseMove, false);   
};

function drawSphere(){ // Sphere geometry
    var geometry, material, sphere;
    geometry = new THREE.SphereBufferGeometry(3, 50, 50, 0, Math.PI * 2, 0, Math.PI * 2);
    material = new THREE.MeshNormalMaterial();
    sphere = new THREE.Mesh(geometry, material);
    return sphere;
};

function drawSpheres(){ // Draw four corners for the quadrant
    sphere1 = drawSphere(); sphere1.position.set(20, 0, 0);
    sphere2 = sphere1.clone(); sphere2.position.set(15, 23, 0);
    sphere3 = sphere1.clone(); sphere3.position.set(0, 22, 0);
    sphere4 = sphere1.clone(); sphere4.position.set(-20, 20, 0);
    console.log(sphere1, sphere2, sphere3, sphere4);
    scene.add(sphere1, sphere2, sphere3, sphere4);
};

function onMouseMove(event){ // Calculate mouse movements
    // Normalized Coordinate System
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
    raycasting(renderer, scene, camera);  
};

function raycasting(renderer, scene, camera){
    raycaster.setFromCamera(mouse, camera); // Update the picking ray with the camera and mouse movements
    intersects = raycaster.intersectObjects([sphere2, sphere3, sphere4]);
    for(var i = 0; i < intersects.length; i++){
        console.log('Hit on: ', intersects[i].object.uuid);
    }
};

在此示例中,光线投射器。每次有鼠标悬停在 intersectObjects()方法中指定的球体上时,您都会在控制台上看到“命中”消息。

2 个答案:

答案 0 :(得分:0)

如果您不是从鼠标光标投射光线,则不需要.setFromCamera()..您只需手动设置光线即可。

您可以使用射线投射检查一个球体是否碰到另一个球体,也可以像这样进行球体->球体相交测试。

var tmp = new THREE.Vector3();
function spheresCollide(centerA,radiusA,centerB,radiusB){
    var sqdist = radiusA+radiusB;
    sqdist*=sqdist;
    tmp.copy(centerB).sub(centerA)
    if(tmp.lengthSq()<sqdist)return true;
    return false;
}

//centerA and centerB are the vector3 positions of your spheres.. radiusA and B are the sphere radii

要进行光线投射,您需要对每个球体执行以下操作:

rayCaster.ray.origin.copy(sphereA.position);
rayCaster.ray.direction.copy(sphereB.position).sub(sphereA.position).normalize()
intersects = raycaster.intersectObjects([sphereB]);
    for(var i = 0; i < intersects.length; i++){
        tmp.copy(intersects[i].position).sub(sphereA.position);
        if(tmp.length()<(radiusA+radiusB)){
            intersects[i].object.material.color.set(0xff0000);
            console.log('Hit on: ', intersects[i]);
         }

    }

答案 1 :(得分:0)

我花了一些时间才能解决这个问题。对移动物体进行光线投射有一些不同之处。射线投射背后的想法是正在投射射线。在此示例中,setFromCamera()方法不会执行操作,因为“球形”应该是射线所来自的对象。

    <script src='https://threejs.org/build/three.min.js'></script>
    <script src='https://threejs.org/examples/js/controls/DragControls.js'></script>
<script>

    window.onload = init;
    // Global variables
    var renderer, raycaster, 
    scene, camera, sphere1, sphere2, 
    sphere3, sphere4, dragControls;

    function init(){
        // Get WebGL ready
        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        renderer = this.renderer;
        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
        camera.position.set(0, 0, 100);
        camera.lookAt(0, 0, 0);
        scene = new THREE.Scene();
        // Get set                
        drawSpheres();
        // Go
        eventful();
        animate();
    };

    function animate(){
        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        raycasting();
    };

    function eventful(){ // Where all events happen
        dragControls = new THREE.DragControls([sphere1], camera, renderer.domElement);
        dragControls.addEventListener('dragstart', onDragStart, false);
        dragControls.addEventListener('dragend', onDragEnd, false);  
    };

    function drawSphere(){ // Sphere geometry
        var geometry, material, sphere;
        geometry = new THREE.CubeGeometry(3,3,3,1,1,1);
        material = new THREE.MeshBasicMaterial({
            wireframe: true
        });
        sphere = new THREE.Mesh(geometry, material);
        return sphere;
    };

    function drawSpheres(){ // Draw four corners for the quadrant
        sphere1 = drawSphere(); sphere1.position.set(20, 0, 0);
        sphere2 = sphere1.clone(); sphere2.position.set(15, 23, 0);
        sphere3 = sphere1.clone(); sphere3.position.set(0, 22, 0);
        sphere4 = sphere1.clone(); sphere4.position.set(-20, 20, 0);
        console.log(sphere1, sphere2, sphere3, sphere4);
        scene.add(sphere1, sphere2, sphere3, sphere4);
    };

    function onDragStart(event){
        console.log('on drag start');
    };

    function onDragEnd(event){
        console.log('on drag end');
    };

    function onMouseMove(event){ // Calculate mouse movements
        // Normalized Coordinate System
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
    };

    //////////////////////////////
    //////// RAYCASTING //////////
    //////////////////////////////

    function raycasting(){ // Blast rays like Cyclops or Superman, but only to measure proximity
        var sphere1Origin, // The 3D position of sphere1 when the page loads
        vIndex, // Vertex index
        sphere1VLength, // The amount of vertices
        dVector, // The directions the ray should be pointing to while it is moving
        raycaster, // The ray casting from a given point
        sphere1Origin = getUpdatedPosition();
        sphere1VLength = sphere1.geometry.vertices.length;
        for(vIndex = 0; vIndex < sphere1VLength; vIndex++){
            dVector = bindRaysToVertices(sphere1, vIndex);
            raycaster = raycast(sphere1Origin, dVector);
            collided = detectCollision(raycaster, dVector).hasCollided;
            if(collided){
                console.log('Hit!');
            }
        }
    };

    function detectCollision(raycaster, dVector){ // Determines whether there is/are (a) collision(s)
        var collisions, // Results of each collisions
        collided; // True/False
        collisions = raycaster.intersectObjects([sphere2, sphere3, sphere4]);
        collided = collisions.length > 0 && collisions[0].distance < dVector.length();
        return {
            hasCollided: collided,
            collisionsList: collisions
        };
    };

    function bindRaysToVertices(sphere1, vIndex){ // Make the geometry blast rays in all directions, while moving
        var lVertex, // The re-calculated (updated) vertices for the moving object
        gVertex, // The complete representation of the re-calculated (updated) vertices
        dVector; // The directions the ray should be pointing to while it is moving
        lVertex = sphere1.geometry.vertices[vIndex].clone();
        gVertex = lVertex.applyMatrix4(sphere1.matrix);
        dVector = gVertex.sub(sphere1.position);
        return dVector;
    };

    function getUpdatedPosition(){
        var sphere1Origin, // The 3D position of sphere1 when the page loads
        sphere1Origin = sphere1.position.clone();
        return sphere1Origin;
    };

    function raycast(sphere1Origin, dVector){
        // Make the sphere cast the ray, through its vertices, 
        // while moving, using a Normalized Coordinate System
        return new THREE.Raycaster(sphere1Origin, toNCS(dVector));
    };

    function toNCS(dVector){ // To Normalize Coordinate System
        return dVector.clone().normalize();
    };

</script>

Stemkoski为例,我决定将多维数据集用作线框,并且如果需要有一个球体,则该多维数据集应位于其中。否则,为了接近检测目的而具有像太阳这样的球体爆炸射线将在计算上昂贵。