Zoeken…


Objectpicken / Raycasting

Raycasting betekent een straal van de muispositie op het scherm naar de scène gooien, dit is hoe threejs bepaalt op welk object je wilt klikken als je het hebt geïmplementeerd. Threejs krijgt die informatie met behulp van een octree , maar nog steeds in productie wil je misschien niet om het resultaat te berekenen op elk frame of op de mousemove evenement, maar veeleer op de click evenement voor een meer toegankelijke app met lage eisen.

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

init();

function init () {

    //Usual setup code here.

    raycaster = new THREE.Raycaster();
    renderer.domElement.addEventListener( 'click', raycast, false );

    //Next setup code there.

}

function raycast ( e ) {

    //1. sets the mouse position with a coordinate system where the center
    //   of the screen is the origin
    mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;

    //2. set the picking ray from the camera position and mouse coordinates
    raycaster.setFromCamera( mouse, camera );    

    //3. compute intersections
    var intersects = raycaster.intersectObjects( scene.children );

    for ( var i = 0; i < intersects.length; i++ ) {
        console.log( intersects[ i ] ); 
        /*
            An intersection has the following properties :
                - object : intersected object (THREE.Mesh)
                - distance : distance from camera to intersection (number)
                - face : intersected face (THREE.Face3)
                - faceIndex : intersected face index (number)
                - point : intersection point (THREE.Vector3)
                - uv : intersection point in the object's UV coordinates (THREE.Vector2)
        */
    }

}

VOORZICHTIGHEID! U kunt uw tijd verliezen om naar het lege scherm te kijken als u het volgende deel niet leest.

Als u de raycaster.intersectObjects( scene.children ); wilt detecteren, stelt u de tweede parameter van raycaster.intersectObjects( scene.children ); naar waar.

Het betekent raycaster.intersectObjects( scene.children , true);

De raycast-code detecteert alleen de helper.

Als u wilt dat het normale objecten evenals een helper detecteert, moet u de bovenstaande raycast-functie opnieuw kopiëren. Zie deze vraag .

De volledige raycast-code is

function raycast ( e ) {
// Step 1: Detect light helper
    //1. sets the mouse position with a coordinate system where the center
    //   of the screen is the origin
    mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;

    //2. set the picking ray from the camera position and mouse coordinates
    raycaster.setFromCamera( mouse, camera );    

    //3. compute intersections (note the 2nd parameter)
    var intersects = raycaster.intersectObjects( scene.children, true );

    for ( var i = 0; i < intersects.length; i++ ) {
        console.log( intersects[ i ] ); 
        /*
            An intersection has the following properties :
                - object : intersected object (THREE.Mesh)
                - distance : distance from camera to intersection (number)
                - face : intersected face (THREE.Face3)
                - faceIndex : intersected face index (number)
                - point : intersection point (THREE.Vector3)
                - uv : intersection point in the object's UV coordinates (THREE.Vector2)
        */
    }
// Step 2: Detect normal objects
    //1. sets the mouse position with a coordinate system where the center
    //   of the screen is the origin
    mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
    mouse.y = - ( e.clientY / window.innerHeight ) * 2 + 1;

    //2. set the picking ray from the camera position and mouse coordinates
    raycaster.setFromCamera( mouse, camera );    

    //3. compute intersections (no 2nd parameter true anymore)
    var intersects = raycaster.intersectObjects( scene.children );

    for ( var i = 0; i < intersects.length; i++ ) {
        console.log( intersects[ i ] ); 
        /*
            An intersection has the following properties :
                - object : intersected object (THREE.Mesh)
                - distance : distance from camera to intersection (number)
                - face : intersected face (THREE.Face3)
                - faceIndex : intersected face index (number)
                - point : intersection point (THREE.Vector3)
                - uv : intersection point in the object's UV coordinates (THREE.Vector2)
        */
    }

}

Object kiezen / GPU

Het kiezen van objecten met Raycasting kan een zware taak zijn voor uw CPU, afhankelijk van uw setup (bijvoorbeeld als u geen octree achtige setup hebt) en het aantal objecten in de scène.

Als u de wereldcoördinaten onder de muiscursor niet nodig hebt, maar alleen om het object eronder te identificeren, kunt u GPU-picking gebruiken.

Korte uitleg, GPU kan een krachtig hulpmiddel voor berekening zijn, maar u moet weten hoe u de resultaten terug kunt krijgen. Het idee is dat als u de objecten een kleur geeft die hun id weergeeft, u de kleur van de pixel onder de cursor kunt lezen en de id van het gekozen object kunt achterhalen. Onthoud dat RGB slechts een hexadecimale waarde is, dus er is een conversie tussen id (geheel getal) en kleur (hexadecimaal).

  1. Maak een nieuwe scène en een nieuw renderingdoel voor uw object
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
    pickingTexture.texture.minFilter = THREE.LinearFilter;
  1. Maak een nieuw arceringmateriaal voor het kiezen van objecten;
var vs3D = `
attribute vec3 idcolor;
varying vec3 vidcolor;
void main(){
vidcolor = idcolor;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
}`;

var fs3D = `
varying vec3 vidcolor;
void main(void) {
gl_FragColor = vec4(vidcolor,1.0);
}`;

var pickingMaterial = new THREE.ShaderMaterial(
    {
        vertexShader: vs3D,
        fragmentShader: fs3D,
        transparent: false,
        side: THREE.DoubleSide
    });
  1. Voeg uw mesh / lijngeometrieën een nieuw kenmerk toe dat hun id in RGB vertegenwoordigt, maak het pickingObject met dezelfde geometrie en voeg het toe aan de picking scene, en voeg de werkelijke mesh toe aan een id-> objectwoordenboek
var selectionObjects = [];

for(var i=0; i<myMeshes.length; i++){
    var mesh = myMeshes[i];
    var positions = mesh.geometry.attributes["position"].array;
    var idColor = new Float32Array(positions.length);

    var color = new THREE.Color();
    color.setHex(mesh.id);

    for (var j=0; j< positions.length; j+=3){
        idColor[j] = color.r;
        idColor[j+1] = color.g;
        idColor[j+2] = color.b;
    }

    mesh.geometry.addAttribute('idcolor', new THREE.BufferAttribute(idColor, 3));

    var pickingObject = new THREE.Mesh(mesh.geometry, pickingMaterial);
    
    pickingScene.add(pickingObject);
    selectionObjects[mesh.id] = mesh;
}
  1. Ten slotte, op uw muisklikhandler
renderer.render(pickingScene, camera, pickingTexture);
var pixelBuffer = new Uint8Array(4);
renderer.readRenderTargetPixels(pickingTexture, event.pageX, pickingTexture.height - event.pageY, 1, 1, pixelBuffer);
var id = (pixelBuffer[0] << 16) | (pixelBuffer[1] << 8) | (pixelBuffer[2]);

if (id>0){
    //this is the id of the picked object
}else{
    //it's 0. clicked on an empty space
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow