簡體   English   中英

three.js 中的 Raycaster 故障

[英]Raycaster malfunctioning in three.js

我正在創建一個游戲,玩家可以從第一人稱視角四處移動,其中地面是由 Perlin 噪聲生成的,因此不平坦。 我想在游戲中模擬重力。 因此,實現了一個光線投射的東西,它應該找到玩家與地面的距離,並在他們撞到地面時阻止他們墜落。 這是我的代碼(如果狙擊手不清楚,請訪問https://3d.211368e.repl.co ):

 const scene = new THREE.Scene(), camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 10000000000000), renderer = new THREE.WebGLRenderer(), canvas = renderer.domElement; camera.rotation.order = "YXZ"; renderer.setSize(window.innerWidth, window.innerHeight); renderer.shadowMap.enabled = true; renderer.shadowMapType = THREE.PCFSoftShadowMap; document.body.appendChild(canvas); const light = new THREE.DirectionalLight( 0xffffff, 1); light.position.set(0, 10000, 0); light.castShadow = true; light.shadow.camera.top = 10000; light.shadow.camera.right = 10000; light.shadow.camera.bottom = -10000; light.shadow.camera.left = -10000; light.shadow.camera.far = 100000; wwwww scene.add(light); var sky = new THREE.Mesh(new THREE.SphereGeometry(100000, 3, 3, 0, Math.PI, 0, Math.PI), new THREE.MeshBasicMaterial({color: 0x579ebb})); sky.material.side = THREE.BackSide; sky.rotateX(-Math.PI / 2); scene.add(sky); class Vector2{ constructor(x, y){ this.x = x; this.y = y; } dot(other){ return this.x * other.x + this.y * other.y; } } function Shuffle(tab){ for(let e = tab.length-1; e > 0; e--){ let index = Math.round(Math.random() * (e-1)), temp = tab[e]; tab[e] = tab[index]; tab[index] = temp; } } function MakePermutation(){ let P = []; for(let i = 0; i < 256; i++){ P.push(i); } Shuffle(P); for(let i = 0; i < 256; i++){ P.push(P[i]); } return P; } let P = MakePermutation(); function GetConstantVector(v){ let h = v & 3; if(h == 0) return new Vector2(1.0, 1.0); if(h == 1) return new Vector2(-1.0, 1.0); if(h == 2) return new Vector2(-1.0, -1.0); return new Vector2(1.0, -1.0); } function Fade(t){ return ((6 * t - 15) * t + 10) * t ** 3; } function Lerp(t, a1, a2){ return a1 + t*(a2-a1); } function Noise2D(x, y){ let X = Math.floor(x) & 255; let Y = Math.floor(y) & 255; let xf = x - Math.floor(x); let yf = y - Math.floor(y); let topRight = new Vector2(xf - 1, yf - 1); let topLeft = new Vector2(xf, yf - 1); let bottomRight = new Vector2(xf - 1, yf); let bottomLeft = new Vector2(xf, yf); let valueTopRight = P[P[X+1]+Y+1]; let valueTopLeft = P[P[X]+Y+1]; let valueBottomRight = P[P[X+1]+Y]; let valueBottomLeft = P[P[X]+Y]; let dotTopRight = topRight.dot(GetConstantVector(valueTopRight)); let dotTopLeft = topLeft.dot(GetConstantVector(valueTopLeft)); let dotBottomRight = bottomRight.dot(GetConstantVector(valueBottomRight)); let dotBottomLeft = bottomLeft.dot(GetConstantVector(valueBottomLeft)); let u = Fade(xf); let v = Fade(yf); return Lerp(u, Lerp(v, dotBottomLeft, dotTopLeft), Lerp(v, dotBottomRight, dotTopRight)); } const plane = new THREE.Mesh(new THREE.PlaneGeometry(10000, 10000, 500, 500), new THREE.MeshPhongMaterial({color: 0x00aa00})); plane.rotateX(-Math.PI / 2 + 0.00001); plane.receiveShadow = true; for (let y = 0, i = 0; y < 501; y++){ for(let x = 0; x < 501; x++, i++){ let n = 0.0, a = 1.0, f = 0.005; for (let o = 0; o < 3; o++){ let v = a*Noise2D(x*f, y*f); n += v; a *= 0.5; f *= 2.0; } n += 1; n /= 2; plane.geometry.vertices[i].z = n * 1000; } } scene.add(plane); const point = plane.geometry.vertices[Math.floor(Math.random() * 1000)]; camera.position.set(point.x, point.z + 2, point.y); const geo = new THREE.Mesh(new THREE.BoxGeometry(10, 10, 10), new THREE.MeshBasicMaterial({color: 0xff0000})); geo.castShadow = true; scene.add(geo); const render = () => { requestAnimationFrame(render); const below = new THREE.Vector3(camera.position.x, -1000000, camera.position.y), cast = new THREE.Raycaster(camera.position, below), intersect = cast.intersectObject(plane); if (intersect.length > 0){ if (intersect[0].distance < 3) camera.translateY(-1); }else{ camera.translateY(-1); } renderer.render(scene, camera); } render(); onmousemove = () => { if (camera.rotation._x > -0.8 || camera.rotation._y > -0.8){ camera.rotateX(-Math.atan(event.movementY / 300)); camera.rotateY(-Math.atan(event.movementX / 300)); }else{ if (Math.atan(event.movementY / 300) < 0) camera.rotateX(-Math.atan(event.movementY / 300)); if (Math.atan(event.movementX / 300) < 0) camera.rotateY(-Math.atan(event.movementX / 300)); } camera.rotation.z = 0; } onresize = () => { renderer.setSize(window.innerWidth, window.innerHeight); canvas.width = window.innerWidth; canvas.height = window.innerHeight; camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(); } onkeydown = (event) => { if (event.key == "w") camera.translateZ(-10); if (event.key == "a") camera.translateX(-1); if (event.key == "s") camera.translateZ(1); if (event.key == "d") camera.translateX(1); if (event.key == "ArrowUp") camera.translateY(1); if (event.key == "ArrowDown") camera.translateY(-1); }
 body{ margin: 0; background-color: black; overflow: hidden; } canvas{ border: none; }
 <meta name="viewport" content="width=device-width"> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/94/three.min.js"></script> <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/controls/OrbitControls.js"></script> <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/utils/SceneUtils.js"></script> <script src="https://cdn.rawgit.com/mrdoob/three.js/0949e59f/examples/js/libs/dat.gui.min.js"></script>

如果在攝像機下方至少 3 個單位處未檢測到地面,則玩家將繼續下落。 然而,有時在攝像機下方沒有發現任何東西,而玩家顯然是在地面上盤旋。 這非常令人沮喪。 有沒有可靠的替代方法來解決這個問題,比如使用光線投射以外的方法? 還是代碼中有錯誤? TIA

Raycaster 正在采用標准化方向,所以像這樣使用它

new THREE.Raycaster(camera.position, below.normalize())

請參閱Raycaster 文檔 構造函數采用原點、方向和近、遠參數。 所以你可以這樣做:

const gravityDirection = new THREE.Vector(0, -1, 0);
cast = new THREE.Raycaster(camera.position, gravityDirection, 0, 3);

這也使得距離檢查變得多余,因為far參數已經過濾掉了比3個單位更遠的命中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM