Suche…


Objektauswahl / Raycasting

Raycasting bedeutet, einen Strahl von der Mausposition auf dem Bildschirm in die Szene zu werfen. Auf diese Weise bestimmt dreijs, auf welches Objekt Sie klicken möchten, wenn Sie es implementiert haben. Threejs ruft diese Informationen über einen Octree ab , aber während der Produktion möchten Sie möglicherweise nicht das Ergebnis bei jedem Frame oder beim mousemove Ereignis mousemove , sondern eher beim click Ereignis für eine besser zugängliche App mit geringen Anforderungen.

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)
        */
    }

}

VORSICHT! Sie könnten Ihre Zeit verlieren, wenn Sie den leeren Bildschirm betrachten, wenn Sie den nächsten Teil nicht lesen.

Wenn Sie den raycaster.intersectObjects( scene.children ); erkennen möchten, legen Sie den zweiten Parameter von raycaster.intersectObjects( scene.children ); um wahr zu sein.

Es bedeutet raycaster.intersectObjects( scene.children , true);

Der Raycast-Code erkennt nur den Light Helper.

Wenn Sie sowohl normale Objekte als auch Light Helper erkennen möchten, müssen Sie die obige Raycast-Funktion erneut kopieren. Siehe diese Frage .

Der vollständige Raycast-Code lautet

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)
        */
    }

}

Objektauswahl / GPU

Die Objektauswahl mit Raycasting kann für Ihre CPU eine schwere Aufgabe sein, abhängig von Ihrem Setup (zum Beispiel, wenn Sie kein Octree-ähnliches Setup haben) und der Anzahl der Objekte in der Szene.

Wenn Sie nicht die Weltkoordinaten unter dem Mauszeiger benötigen, sondern nur zur Identifizierung des Objekts darunter, können Sie die GPU-Auswahl verwenden.

Kurze Erklärung, GPU kann ein leistungsfähiges Werkzeug für die Berechnung sein, aber Sie müssen wissen, wie Sie die Ergebnisse zurückbekommen. Die Idee ist, wenn Sie die Objekte mit einer Farbe rendern, die ihre ID darstellt, können Sie die Farbe des Pixels unter dem Cursor lesen und die ID des ausgewählten Objekts herausfinden. Denken Sie daran, dass RGB nur ein Hexadezimalwert ist, daher gibt es eine Konvertierung zwischen ID (Ganzzahl) und Farbe (Hexadezimalwert).

  1. Erstellen Sie eine neue Szene und ein neues Rendering-Ziel für Ihr Objekt
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
    pickingTexture.texture.minFilter = THREE.LinearFilter;
  1. Erstellen Sie ein neues Shader-Material für die Objektauswahl.
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. Fügen Sie Ihren Netz- / Liniengeometrien ein neues Attribut hinzu, das ihre ID in RGB darstellt, erstellen Sie das pickingObject mit derselben Geometrie, fügen Sie es der Kommissionierszene hinzu und fügen Sie das tatsächliche Netz einem id-> Objektverzeichnis hinzu
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. Schließlich auf Ihrem Mausklick-Handler
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
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow