2017-09-06 6 views
0

J'utilise cet exemple pour mon cube panorama WebGL: https://threejs.org/examples/?q=pano#webgl_panorama_equirectangularThree.js: raycast A un tableau vide de Intersecte

Je veux savoir ce que l'utilisateur clique sur le cube et je découvre que je peux utiliser raycaster pour cela. Selon docs, j'ai ajouté la fonction suivante:

function onMouseDown(event) { 
     event.preventDefault(); 

     var mouseVector = new THREE.Vector3(
      (event.clientX/window.innerWidth) * 2 - 1, 
      - (event.clientY/window.innerHeight) * 2 + 1, 
      1); 

     //projector.unprojectVector(mouseVector, camera); 
     mouseVector.unproject(camera); 
     var raycaster = new THREE.Raycaster(camera.position, mouseVector.sub(camera.position).normalize()); 

     // create an array containing all objects in the scene with which the ray intersects 
     var intersects = raycaster.intersectObjects(scene.children); 
     console.log(intersects); 
     if (intersects.length>0){ 
      console.log("Intersected object:", intersects.length); 
      intersects[ 0 ].object.material.color.setHex(Math.random() * 0xffffff); 
     } 
     // ... 

Mais intersects est toujours vide. Ma scène est définie comme

scene = new THREE.Scene(); 

et a Skybox ajouté:

var skyBox = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), materials); 
skyBox.applyMatrix(new THREE.Matrix4().makeScale(1, 1, - 1)); 
scene.add(skyBox); 

J'ai vu des postes similaires liés à cette question, mais ne pouvait pas comprendre comment appliquer cet exemple. Toutes les directions sont appréciées.

Répondre

1

Essayez d'ajouter ceci à votre définition matérielle:

var materials = new THREE.SomeMaterial({ 
    /* other settings */, 
    side: THREE.DoubleSide 
}); 

Raycaster ne sera pas recouper des faces arrières sauf si la propriété est définie sur sideTHREE.BackSide ou THREE.DoubleSide. Même si votre mise à l'échelle inverse techniquement la direction du visage, l'ordre des sommets reste le même, ce qui est important pour Raycaster.

Quelques explications plus

L'extrait ci-dessous montre comment un rayon projeté à partir d'un appareil photo au centre d'un skybox inversé par une échelle -Z pourrait ressembler.

La boîte elle-même semble bizarre car elle a été mise à l'échelle -Z et les normales ne correspondent plus au matériau. Mais c'est ici ou là.

La flèche verte représente le rayon d'origine. La flèche rouge représente ce qui arrivera à ce rayon à l'intérieur de la fonction Mesh.raycast, qui appliquera l'inverse de la matrice du monde de l'objet au rayon, mais pas à la géométrie de l'objet. C'est un problème complètement différent. Le point que je fais est que dans Mesh.raycast, il n'affecte pas l'ordre vertex/index, donc quand il vérifie les triangles du maillage, ils sont toujours dans leur ordre d'origine. Pour une norme BoxGeometry/BoxBufferGeometry, cela signifie que les faces sont toutes orientées vers l'extérieur à partir de l'origine géométrique. Cela signifie que les rayons (quelle que soit la façon dont la matrice de transformation les affecte) essaient toujours d'intersecter la face arrière de ces triangles, ce qui ne fonctionnera que si le matériau est défini sur THREE.DoubleSide. (Il peut également être réglé sur THREE.BackSide, mais l'échelle -Z le gâchera.)

Cliquer sur l'un des boutons raycast produira 0 intersections si la case -Z n'est pas définie sur THREE.DoubleSide (par défaut). Cliquez sur le bouton "Set THREE.DoubleSide" et essayez à nouveau - il va maintenant se croiser.

var renderer, scene, camera, controls, stats; 
 

 
var WIDTH = window.innerWidth, 
 
\t HEIGHT = window.innerHeight, 
 
\t FOV = 35, 
 
\t NEAR = 1, 
 
\t FAR = 1000, 
 
    ray1, ray2, mesh; 
 

 
function populateScene(){ 
 
\t var cubeGeo = new THREE.BoxBufferGeometry(10, 10, 10), 
 
\t \t cubeMat = new THREE.MeshPhongMaterial({ color: "red", transparent: true, opacity: 0.5 }); 
 
\t mesh = new THREE.Mesh(cubeGeo, cubeMat); 
 
    mesh.applyMatrix(new THREE.Matrix4().makeScale(1, 1, -1)); 
 
    mesh.updateMatrixWorld(true); 
 
\t scene.add(mesh); 
 
    
 
    var dir = new THREE.Vector3(0.5, 0.5, 1); 
 
    dir.normalize(); 
 
    ray1 = new THREE.Ray(new THREE.Vector3(), dir); 
 
    
 
    var arrow1 = new THREE.ArrowHelper(ray1.direction, ray1.origin, 20, 0x00ff00); 
 
    scene.add(arrow1); 
 
    
 
    var inverseMatrix = new THREE.Matrix4(); 
 
    inverseMatrix.getInverse(mesh.matrixWorld); 
 
    
 
    ray2 = ray1.clone(); 
 
    ray2.applyMatrix4(inverseMatrix); 
 
    
 
    var arrow2 = new THREE.ArrowHelper(ray2.direction, ray2.origin, 20, 0xff0000); 
 
    scene.add(arrow2); 
 
} 
 

 
function init() { 
 
\t document.body.style.backgroundColor = "slateGray"; 
 

 
\t renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); 
 

 
\t document.body.appendChild(renderer.domElement); 
 
\t document.body.style.overflow = "hidden"; 
 
\t document.body.style.margin = "0"; 
 
\t document.body.style.padding = "0"; 
 

 
\t scene = new THREE.Scene(); 
 

 
\t camera = new THREE.PerspectiveCamera(FOV, WIDTH/HEIGHT, NEAR, FAR); 
 
\t camera.position.z = 50; 
 
\t scene.add(camera); 
 

 
\t controls = new THREE.TrackballControls(camera, renderer.domElement); 
 
\t controls.dynamicDampingFactor = 0.5; 
 
\t controls.rotateSpeed = 3; 
 

 
\t var light = new THREE.PointLight(0xffffff, 1, Infinity); 
 
\t camera.add(light); 
 

 
\t stats = new Stats(); 
 
\t stats.domElement.style.position = 'absolute'; 
 
\t stats.domElement.style.top = '0'; 
 
\t document.body.appendChild(stats.domElement); 
 

 
\t resize(); 
 
\t window.onresize = resize; 
 

 
\t populateScene(); 
 

 
\t animate(); 
 
    
 
    var rayCaster = new THREE.Raycaster(); 
 
    document.getElementById("greenCast").addEventListener("click", function(){ 
 
    rayCaster.ray.copy(ray1); 
 
    alert(rayCaster.intersectObject(mesh).length + " intersections!"); 
 
    }); 
 
    document.getElementById("redCast").addEventListener("click", function(){ 
 
    rayCaster.ray.copy(ray2); 
 
    alert(rayCaster.intersectObject(mesh).length + " intersections!"); 
 
    }); 
 
    document.getElementById("setSide").addEventListener("click", function(){ 
 
    mesh.material.side = THREE.DoubleSide; 
 
    mesh.material.needsUpdate = true; 
 
    }); 
 
} 
 

 
function resize() { 
 
\t WIDTH = window.innerWidth; 
 
\t HEIGHT = window.innerHeight; 
 
\t if (renderer && camera && controls) { 
 
\t \t renderer.setSize(WIDTH, HEIGHT); 
 
\t \t camera.aspect = WIDTH/HEIGHT; 
 
\t \t camera.updateProjectionMatrix(); 
 
\t \t controls.handleResize(); 
 
\t } 
 
} 
 

 
function render() { 
 
\t renderer.render(scene, camera); 
 
} 
 

 
function animate() { 
 
\t requestAnimationFrame(animate); 
 
\t render(); 
 
\t controls.update(); 
 
\t stats.update(); 
 
} 
 

 
function threeReady() { 
 
\t init(); 
 
} 
 

 
(function() { 
 
\t function addScript(url, callback) { 
 
\t \t callback = callback || function() { }; 
 
\t \t var script = document.createElement("script"); 
 
\t \t script.addEventListener("load", callback); 
 
\t \t script.setAttribute("src", url); 
 
\t \t document.head.appendChild(script); 
 
\t } 
 

 
\t addScript("https://threejs.org/build/three.js", function() { 
 
\t \t addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function() { 
 
\t \t \t addScript("https://threejs.org/examples/js/libs/stats.min.js", function() { 
 
\t \t \t \t threeReady(); 
 
\t \t \t }) 
 
\t \t }) 
 
\t }) 
 
})();
body{ 
 
    text-align: center; 
 
}
<input id="greenCast" type="button" value="Cast Green"> 
 
<input id="redCast" type="button" value="Cast Red"> 
 
<input id="setSide" type="button" value="Set THREE.DoubleSide">

+0

Cette solution a fonctionné! – Vad

0

Vous pouvez réellement utiliser un processus plus facile de déterminer votre rayon de la caméra:

THREE.Raycaster.prototype.setFromCamera(Vector2, Camera); 

définir simplement les coordonnées de votre souris comme vous le faites dans un Vector2, puis passez les éléments au Raycaster et laissez-le faire. Il cache la complexité d'intersection du frustrum avec le rayon de la caméra, et devrait résoudre votre problème. (En outre, le raycaster n'intersecte en effet que les faces directement face au rayon, mais puisque votre SkyBox a été inversée, ses faces géométriques pointent vers l'intérieur de la boîte, elles doivent donc se croiser si la caméra est à l'intérieur de la boîte . Une autre possibilité est que votre boîte est plus loin que la valeur par défaut de far raycasters.)

function onMouseDown(event) { 
 

 
    event.preventDefault(); 
 

 
    var mouseVector = new THREE.Vector2(
 
     event.clientX/window.innerWidth * 2 - 1, 
 
     -event.clientY/window.innerHeight * 2 + 1 
 
    ); 
 

 
    var raycaster = new THREE.Raycaster; 
 
    raycaster.setFromCamera(mouseVector, camera); 
 

 
    var intersects = raycaster.intersectObjects(scene.children); 
 
     
 
    console.log(intersects); 
 
     
 
    if(intersects.length > 0){ 
 

 
     console.log("Intersected object:", intersects[ 0 ]); 
 
     intersects[ 0 ].object.material.color.setHex(Math.random() * 0xffffff); 
 

 
    } 
 

 
}

+1

FWIW, 'Raycaster.far' par défaut' Infinity', donc pas de problèmes là-bas. :) – TheJim01

+0

Merci @ chose, votre réponse m'a aussi aidé à comprendre – Vad