我正在拔掉这个头发。我必须为 3D 项目使用特定的相机角度,但必须使用正交相机。为了游戏目的,我需要能够精确地点击地板。 ThreeJS Raycast 似乎无法正常工作(或者我设置了错误的方式?)。在像角度这样的自顶向下视图中,效果更好。
这是一个解释我所处情况的小提琴:https://jsfiddle.net/p6td5oak/42/
const sceneWidth = window.innerWidth;
const sceneHeight = window.innerHeight;
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera( -sceneWidth / 2, sceneWidth / 2, sceneHeight / 2, -sceneHeight / 2, -1000, 1000 );
camera.rotation.set(
-Math.PI / 12,
Math.PI / 12,
Math.PI / 24
);
camera.position.set(0, 1, 0);
camera.zoom = 2;
camera.updateProjectionMatrix();
const renderer = new THREE.WebGLRenderer();
renderer.setSize( sceneWidth, sceneHeight );
document.body.appendChild( renderer.domElement );
const whiteMaterial = new THREE.MeshBasicMaterial({});
const redMaterial = new THREE.MeshBasicMaterial({
color: 0xFF0000
});
const size = 100;
const geometry = new THREE.PlaneGeometry(size, size, 10, 10);
for (var x = 0; x < 2; x++)
{
for (var z = 0; z < 2; z++)
{
let mesh = new THREE.Mesh(geometry, ((x + z) % 2 ? whiteMaterial : redMaterial));
mesh.rotation.set(
-Math.PI / 2,
0,
0
);
mesh.position.set(
x*size,
0,
z*size
)
scene.add(mesh);
}
}
var raycaster = new THREE.Raycaster();
window.addEventListener("pointerup", function(e)
{
var screenPos = new THREE.Vector2();
screenPos.x = (e.clientX / window.innerWidth) * 2 - 1;
screenPos.y = - (e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(screenPos, camera);
var rays = raycaster.intersectObjects(scene.children, true);
for (var i = 0; i < rays.length; i++)
{
scene.remove(rays[i].object);
}
}
.bind(this));
function animate() {
requestAnimationFrame( animate );
renderer.render( scene, camera );
}
animate();
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
在示例中,我尝试在单击平面后立即将其移除。如您所见,如果您单击左上角,则可以移除顶部的两个平面。其他两个甚至无法触发。
如果有人知道发生了什么,你就是我的英雄。
谢谢!
PS:我对 ThreeJS 有基本的了解,但我远非专家
答案 0 :(得分:1)
Raycaster
只检测相机前面的物体,而你的相机位于原点附近。将相机向后移动。
此外,您的正交相机的 near
值无效。来自documentation:
有效范围在 0 和远平面的当前值之间。
不支持负值。
const sceneWidth = window.innerWidth;
const sceneHeight = window.innerHeight;
const scene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-sceneWidth / 2, sceneWidth / 2, sceneHeight / 2, -sceneHeight / 2, 0.1, 1000);
camera.rotation.set(
-Math.PI / 12,
Math.PI / 12,
Math.PI / 24
);
camera.position.set(100, 100, 500);
camera.zoom = 2;
camera.updateProjectionMatrix();
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(sceneWidth, sceneHeight);
document.body.appendChild(renderer.domElement);
const whiteMaterial = new THREE.MeshBasicMaterial();
const redMaterial = new THREE.MeshBasicMaterial({
color: 0xFF0000
});
const size = 100;
const geometry = new THREE.PlaneGeometry(size, size, 10, 10);
for (let x = 0; x < 2; x++) {
for (let z = 0; z < 2; z++) {
let mesh = new THREE.Mesh(geometry, ((x + z) % 2 ? whiteMaterial : redMaterial));
mesh.rotation.set(
-Math.PI / 2,
0,
0
);
mesh.position.set(
x * size,
0,
z * size
)
scene.add(mesh);
}
}
const raycaster = new THREE.Raycaster();
const screenPos = new THREE.Vector2();
renderer.domElement.addEventListener("pointerup", function(e) {
screenPos.x = (e.clientX / window.innerWidth) * 2 - 1;
screenPos.y = -(e.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(screenPos, camera);
const intersections = raycaster.intersectObject(scene, true);
for (let i = 0; i < intersections.length; i++) {
scene.remove(intersections[i].object);
}
});
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
animate();
body {
margin: 0;
}
<script src="https://cdn.jsdelivr.net/npm/three@0.129/build/three.js"></script>