Szukaj…


Zbieranie / Raycasting obiektów

Raycasting oznacza rzucanie promienia z pozycji myszy na ekranie na scenę, w ten sposób threejs określa, który obiekt chcesz kliknąć, jeśli go zaimplementowałeś. Threejs pobiera te informacje za pomocą oktetu , ale nadal w produkcji możesz nie chcieć obliczać wyniku dla każdej klatki lub zdarzenia mousemove , ale raczej zdarzenia click , aby uzyskać bardziej dostępną aplikację o niskich wymaganiach.

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

}

UWAGA! Możesz nie tracić czasu, wpatrując się w pusty ekran, jeśli nie czytasz następnej części.

Jeśli chcesz wykryć pomocnika światła, ustaw drugi parametr raycaster.intersectObjects( scene.children ); do prawdy.

Oznacza raycaster.intersectObjects( scene.children , true);

Kod raycast wykryje tylko lekkiego pomocnika.

Jeśli chcesz, aby wykrywała zarówno zwykłe obiekty, jak i lekkiego pomocnika, musisz ponownie skopiować powyższą funkcję raycast. Zobacz to pytanie .

Pełny kod raycast to

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

}

Wybór obiektów / GPU

Wybór obiektów za pomocą Raycasting może być trudnym zadaniem dla twojego procesora, w zależności od konfiguracji (na przykład, jeśli nie masz konfiguracji typu oktree) i liczby obiektów w scenie.

Jeśli nie potrzebujesz współrzędnych świata pod kursorem myszy, a jedynie do zidentyfikowania obiektu pod nim, możesz użyć GPU.

Krótkie wyjaśnienie, GPU może być potężnym narzędziem do obliczeń, ale musisz wiedzieć, jak odzyskać wyniki. Chodzi o to, że jeśli renderujesz obiekty kolorem reprezentującym ich identyfikator, możesz odczytać kolor piksela pod kursorem i znaleźć identyfikator wybranego obiektu. Pamiętaj, że RGB jest tylko wartością szesnastkową, więc istnieje konwersja między id (liczba całkowita) a kolorem (hex).

  1. Utwórz nową scenę i nowy cel renderowania dla swojego obiektu
var pickingScene = new THREE.Scene();
var pickingTexture = new THREE.WebGLRenderTarget(renderer.domElement.clientWidth, renderer.domElement.clientHeight);
    pickingTexture.texture.minFilter = THREE.LinearFilter;
  1. Utwórz nowy materiał modułu cieniującego do pobierania obiektów;
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. Dodaj swoją geometrię siatki / linii nowy atrybut, który reprezentuje ich identyfikator w RGB, utwórz obiekt pickingObject przy użyciu tej samej geometrii i dodaj go do sceny pobrania, a następnie dodaj rzeczywistą siatkę do słownika id-> object
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. Na koniec w module obsługi kliknięć myszą
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
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow