等距视图中正交相机的 ThreeJS 光线投射问题

时间:2021-06-18 19:19:36

标签: three.js

我正在拔掉这个头发。我必须为 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 有基本的了解,但我远非专家

1 个答案:

答案 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>