Three.js:Raycast有一个空的相交数组

时间:2017-09-06 13:55:24

标签: javascript three.js

我将此示例用于我的WebGL全景多维数据集:https://threejs.org/examples/?q=pano#webgl_panorama_equirectangular

我想知道多维数据集用户点击了什么,我发现我可以使用Raycaster。根据文档,我添加了以下功能:

    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 );
        }
        // ...

intersects总是空的。我的场景定义为

scene = new THREE.Scene();

并添加了skyBox:

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

我见过与此问题相关的类似帖子,但无法弄清楚如何应用此示例。任何指示都表示赞赏。

2 个答案:

答案 0 :(得分:1)

尝试将此添加到您的材料定义中:

var materials = new THREE.SomeMaterial({
    /* other settings */,
    side: THREE.DoubleSide
});
除非Raycaster属性设置为sideTHREE.BackSide,否则

THREE.DoubleSide不会与背面相交。即使您的缩放在技术上反转了面部方向,但顶点顺序保持不变,这对Raycaster很重要。

进一步解释

下面的代码段显示了从天空箱中心的相机投射的光线如何以-Z比例反转。

盒子本身看起来很奇怪,因为它已经-Z缩放,法线不再与材质相匹配。但是那里也没有。

绿色箭头表示原始光线。红色箭头表示Mesh.raycast函数内的光线会发生什么,它将对象的世界矩阵的反转应用于光线,但不应用于对象的几何。这是一个完全不同的问题。

我所提出的观点是在Mesh.raycast内,它不会影响顶点/索引顺序,因此当它检查网格的三角形时,它们仍然是原始顺序。对于标准BoxGeometry / BoxBufferGeometry,这意味着所有面都面向几何原点。

这意味着光线(无论变换矩阵如何影响它们)仍然试图与这些三角形的背面相交,除非材质设置为THREE.DoubleSide,否则这些三角形将不起作用。 (它也可以设置为THREE.BackSide,但-Z比例会破坏它。)

如果-Z缩放框未设置为THREE.DoubleSide(默认),则单击任一光线投射按钮将产生0个相交。单击“Set THREE.DoubleSide”按钮并再次尝试 - 它现在将相交。

var renderer, scene, camera, controls, stats;

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

function populateScene(){
	var cubeGeo = new THREE.BoxBufferGeometry(10, 10, 10),
		cubeMat = new THREE.MeshPhongMaterial({ color: "red", transparent: true, opacity: 0.5 });
	mesh = new THREE.Mesh(cubeGeo, cubeMat);
  mesh.applyMatrix( new THREE.Matrix4().makeScale( 1, 1, -1 ) );
  mesh.updateMatrixWorld(true);
	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() {
	document.body.style.backgroundColor = "slateGray";

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

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

	scene = new THREE.Scene();

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

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

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

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

	resize();
	window.onresize = resize;

	populateScene();

	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() {
	WIDTH = window.innerWidth;
	HEIGHT = window.innerHeight;
	if (renderer && camera && controls) {
		renderer.setSize(WIDTH, HEIGHT);
		camera.aspect = WIDTH / HEIGHT;
		camera.updateProjectionMatrix();
		controls.handleResize();
	}
}

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

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

function threeReady() {
	init();
}

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

	addScript("https://threejs.org/build/three.js", function () {
		addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function () {
			addScript("https://threejs.org/examples/js/libs/stats.min.js", function () {
				threeReady();
			})
		})
	})
})();
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">

答案 1 :(得分:0)

您可能实际上想要使用更简单的过程来确定来自相机的光线:

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

只需像在Vector2中一样定义鼠标坐标,然后将元素传递给Raycaster并让它完成它的工作。它隐藏了将截头体与来自相机的光线相交的复杂性,并且应该可以解决您的问题。

(此外,raycaster确实只与面向光线的面相交,但由于你的SkyBox已被反转,其几何面朝向指向框的内部,因此如果相机在框内,它们应相交。另一种可能性是您的盒子比光线队员默认far值更远。)

&#13;
&#13;
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 );

    }

}
&#13;
&#13;
&#13;