在documentation之后很容易弄清楚如何点击网格,但是防止相机穿过网格并不那么容易。我需要一些指导。
如何使用Raycaster阻止相机穿过混乱?
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - interactive cubes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body style="margin:0;overflow:hidden;">
<div style="position:fixed;background:rgba(255,255,255,0.9);" onmouseout="new function(){controls=new function(){this.moveX=0;this.moveY=0;this.moveZ=0;this.rotateX=0;this.rotateY=0;};}"><a href="javascript:void(0);" onmousedown="new function(){controls.moveX=1;clickedIn=false;}" onmouseup="new function(){controls.moveX=0;}">Move Right</a><a href="javascript:void(0);" onmousedown="new function(){controls.moveX-=1;clickedIn=false;}" onmouseup="new function(){controls.moveX=0;}">Move Left</a><a href="javascript:void(0);" onmousedown="new function(){controls.moveY=-1;clickedIn=false;}" onmouseup="new function(){controls.moveY=0;}">Move Down</a><a href="javascript:void(0);" onmousedown="new function(){controls.moveY=1;clickedIn=false;}" onmouseup="new function(){controls.moveY=0;}">Move Up</a><a href="javascript:void(0);" onmousedown="new function(){controls.moveZ=1;clickedIn=false;}" onmouseup="new function(){controls.moveZ=0;}">Move Back</a><a href="javascript:void(0);" onmousedown="new function(){controls.moveZ=-1;clickedIn=false;}" onmouseup="new function(){controls.moveZ=0;}">Move Front</a><a href="javascript:void(0);" onmousedown="new function(){controls.rotateY=1;clickedIn=false;}" onmouseup="new function(){controls.rotateY=0;}">Rotate Right</a><a href="javascript:void(0);" onmousedown="new function(){controls.rotateY=-1;clickedIn=false;}" onmouseup="new function(){controls.rotateY=0;}">Rotate Left</a><a href="javascript:void(0);" onmousedown="new function(){controls.rotateX=1;clickedIn=false;}" onmouseup="new function(){controls.rotateX=0;}">Rotate Up</a><a href="javascript:void(0);" onmousedown="new function(){controls.rotateX=-1;clickedIn=false;}" onmouseup="new function(){controls.rotateX=0;}">Rotate Down</a></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/84/three.min.js"></script>
<script>
var container;
var camera, scene, raycaster, renderer;
var mouse = new THREE.Vector2(),INTERSECTED=[],clickedIn/*bc starts like it was clicked*/=false,controls;
var clock = new THREE.Clock();
init();
animate();
function init() {
controls = new function () {
this.moveX = 0;
this.moveY = 0;
this.moveZ = 0;
this.rotateX = 0;
this.rotateY = 0;
}
container = document.createElement('div');
document.body.appendChild(container);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
var light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(1, 1, 1).normalize();
scene.add(light);
var geometry = new THREE.BoxBufferGeometry(20, 20, 20);
for (var i = 0; i < 50; i++) {
var object = new THREE.Mesh(geometry, new THREE.MeshLambertMaterial({ color: Math.random() * 0xffffff }));
object.name = 'Index:' + i;
object.userData.foo = 'foo';
object.position.x = Math.floor(Math.random() * 201) - 100;
object.position.y = Math.floor(Math.random() * 201) - 100;
object.position.z = Math.floor(Math.random() * 201) - 100;
object.rotation.x = Math.random() * 2 * Math.PI;
object.rotation.y = Math.random() * 2 * Math.PI;
object.rotation.z = Math.random() * 2 * Math.PI;
object.scale.x = Math.random() + 0.5;
object.scale.y = Math.random() + 0.5;
object.scale.z = Math.random() + 0.5;
scene.add(object);
}
raycaster = new THREE.Raycaster();
renderer = new THREE.WebGLRenderer();
renderer.setClearColor(0xf0f0f0);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.sortObjects = false;
container.appendChild(renderer.domElement);
container.addEventListener('click', function (event) {
event.preventDefault();
clickedIn = true;
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
}, false);
window.addEventListener('resize', function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}, false);
}
function animate() {
requestAnimationFrame(animate);
// raycaster
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children);
for (var i = 0; i < INTERSECTED.length; i++) {
INTERSECTED[i].material.emissive.setHex(INTERSECTED[i].currentHex);
INTERSECTED.splice(i, 1);
}
for (var i = 0; clickedIn && i < intersects.length; i++) {
var length = INTERSECTED.push(intersects[0].object) - 1;
INTERSECTED.currentHex = INTERSECTED[length].material.emissive.getHex();
INTERSECTED[length].material.emissive.setHex(0xff0000);
}
// move
var delta = clock.getDelta(), step = 100, stepAngle = (Math.PI / 2);
if (controls.moveX == 1) camera.translateX(step * delta);
else if (controls.moveX == -1) camera.translateX(-step * delta);
if (controls.moveY == 1) camera.translateY(step * delta);
else if (controls.moveY == -1) camera.translateY(-step * delta);
if (controls.moveZ == 1) camera.translateZ(step * delta);
else if (controls.moveZ == -1) camera.translateZ(-step * delta);
if (controls.rotateX == 1) camera.rotateOnAxis(new THREE.Vector3(1, 0, 0), stepAngle * delta);
if (controls.rotateX == -1) camera.rotateOnAxis(new THREE.Vector3(1, 0, 0), -stepAngle * delta);
if (controls.rotateY == 1) camera.rotateOnAxis(new THREE.Vector3(0, 1, 0), stepAngle * delta);
if (controls.rotateY == -1) camera.rotateOnAxis(new THREE.Vector3(0, 1, 0), -stepAngle * delta);
camera.updateMatrixWorld();
// render
renderer.render(scene, camera);
}
</script>
</body>
</html>
答案 0 :(得分:4)
对于第一人称相机,我认为正确的做法是使用相机的边界球并在场景的每个网格上进行测试,但如果你真的想要使用 raycaster ,那么我可以想到两种方法:
在渲染循环中:
再次在渲染循环中:
第一个算法在 O(n)中, n 是场景中的对象数,而第二个算法在 O(1)< / em>但是对于大网格来说可能很棘手。