我按如下方式设置场景:
document.addEventListener('mousedown', onDocumentMouseDown, false);
var container = document.getElementById("myCanvas");
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth*0.99, window.innerHeight*0.99 );
container.appendChild( renderer.domElement );
room_material = new THREE.MeshBasicMaterial({color: 0x00ff00});
room_material.side = THREE.DoubleSide;
objects = [];
camera.position.z = 19;
camera.position.x = 5;
camera.position.y = 30;
我有一个对象数组,我试图检测点击是否与它们相交,定义如下:
var thing0 = new THREE.Shape();
thing0.moveTo(-12.1321728566, 35.3935535858);
thing0.lineTo(7.10021556487,35.3935535858);
thing0.lineTo(7.10021556487,19.7039735578);
thing0.lineTo(5.12636517425,19.7166264449);
thing0.lineTo(5.12636517425,33.6221493891);
thing0.lineTo(-12.1377356984,33.6439534769);
var thing0Geom = new THREE.ShapeGeometry(thing0);
var thing0Mesh = new THREE.Mesh( thing0Geom, room_material );
thing0Mesh.name = "abcd";
scene.add(thing0Mesh);
objects.push(thing0Mesh);
然后我使用以下代码渲染场景:
renderer.render(scene, camera);
requestAnimationFrame(render);
最后我使用以下代码进行鼠标点击事件:
function onDocumentMouseDown(event) {
var vector = new THREE.Vector3(( event.clientX / window.innerWidth ) * 2 - 1, -( event.clientY / window.innerHeight ) * 2 + 1, 0.5);
vector = vector.unproject(camera);
var raycaster = new THREE.Raycaster(camera.position, vector.sub(camera.position).normalize());
var intersects = raycaster.intersectObjects(objects, true);
alert("well, you clicked!");
if (intersects.length > 0) {
alert("wow, it worked");
}
}
但是,无论我做什么,警报都会在raycaster.intersectObjects(objects, true);
跟随时被调用。但是当它放在它之前的任何地方时它会被调用。在这种情况下raycaster.intersectObjects(objects, true);
似乎有点黑洞?
我认为我的设置中只是出了点问题?任何帮助将不胜感激!
答案 0 :(得分:2)
我想我发现了这个问题。我必须将网格添加到一个额外的数组。在scene.children上的一个intersectObjects不起作用,因为那里有其他对象与网格。
所以当我给intersectObjects(mesh [])一个网格数组而不是它工作时。
有关更多代码详细信息,请参阅https://github.com/mrdoob/three.js/issues/8081
答案 1 :(得分:0)
这是一个老问题,但我遇到了类似的问题,并认为我学到的东西可能会帮助别人。我的代码设置与JohnnyDevNull非常相似,所以我不再重复了。
在我的情况下,使用intersectObjects
调用scene.children
不起作用,因为它会选择ambientLighting
等其他对象。我相信这是OP在他自己的回答中提到的内容
下面的函数采用一个空数组(intersects
)。它在场景中的每个子节点中搜索THREE Group对象和Mesh对象,并将Mesh对象添加到数组中。对于组,它将递归设置为true
,将.intersectObject
应用于每个子项。构建阵列后,它会调用阵列上提供的回调函数。
function raycastMeshes(intersects, callback, theScene, theRaycaster) {
var scene = theScene || scene || new THREE.Scene();
var raycaster = theRaycaster || raycaster || new THREE.Raycaster();
for (var i in scene.children) {
if (scene.children[i] instanceof THREE.Group) {
intersects = raycaster.intersectObjects(scene.children[i].children, true);
} else if (scene.children[i] instanceof THREE.Mesh) {
intersects.push(raycaster.intersectObject(scene.children[i]));
}
}
if (intersects.length > 0) {
return callback(intersects);
} else {
return null;
}
}
这显然是一个相当幼稚和具体的用例,但如果您遇到类似问题,应该作为启动板。
答案 2 :(得分:0)
我尝试过两件事起作用:
1)如果网格面未指向射线的原点,请确保使用Three.DoubleSide
。这直接来自documentation:
“请注意,对于网格,必须将面指向射线的原点才能进行检测;穿过面背面的射线的交点将不会被检测到。要对物体的两个面进行射线投射,您需要将材质的side属性设置为THREE.DoubleSide。”
2)在进行光线投射之前,请使用mesh.updateMatrixWorld()。这来自另一个stackoverflow帖子:threejs raycasting does not work
mesh.updateMatrixWorld(); // add this
raycaster.set(from, direction);