簡體   English   中英

Three.js OrbitControls 繞環旋轉

[英]Three.js OrbitControls Rotating Around a ring

我有一個圍繞點旋轉的 OrbitControls 相機:target = player.position.x, y and z。 這很好,但玩家就在屏幕中央。 我需要一個相機圍繞一個環旋轉......第一張圖片:目標在中心,第二張:目標總是放在中心的左邊

讓我解釋一下:這是我的代碼:

controls.target.x = player.position.x;
controls.target.y = player.position.y+3;
controls.target.z = player.position.z;

所以我們圍繞一個固定的點旋轉。

但我需要一個點,它根據 control.getAzimuthalAngle() 或其他東西改變其位置。 相機必須像 GTA V 或其他游戲中一樣,玩家不在屏幕中央,而是向左一點,這樣更方便,例如瞄准,玩家不會干擾瞄准中心。

幫助...

通常對於第三人稱相機,您會不斷將相機對准玩家(或與玩家的一些偏移,或連接到玩家的某些物體)

然后你讓相機隨着時間的推移跟隨玩家。

在下面的代碼中,有一個跟隨玩家的cameraRig 相機裝備就在那里,所以我們不需要做任何數學運算來保持相機高於地面。 類似地,還有一個附加到播放器的camTarget 這就是相機看起來與肩同高的原因。

 function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({canvas}); const keys = {}; const scene = new THREE.Scene(); const fov = 75; const aspect = 2; // the canvas default const near = 0.1; const far = 500; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); // put the camera 5 units above the rig const cameraRig = new THREE.Object3D(); cameraRig.add(camera); camera.position.y = 5; scene.add(cameraRig); cameraRig.position.z = 5; { const color = 0xFFFFFF; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); scene.add(light); } { const size = 200; const divisions = 100; const gridHelper = new THREE.GridHelper(size, divisions); scene.add(gridHelper); } const boxWidth = 0.5; const boxHeight = 2; const boxDepth = 0.5; const geometry = new THREE.CylinderGeometry(boxWidth, boxDepth, boxHeight); const material = new THREE.MeshPhongMaterial({color:'red'}); const cube = new THREE.Mesh(geometry, material); const player = new THREE.Object3D(); const camTarget = new THREE.Object3D(); cube.position.y = boxHeight / 2; // move cube above ground player.add(cube); camTarget.position.y = boxHeight * 3 / 2; // target 2/3ds up the player player.add(camTarget); scene.add(player); function resizeRendererToDisplaySize(renderer) { const canvas = renderer.domElement; const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width || canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize; } const moveDir = new THREE.Vector3(); const camTargetPos = new THREE.Vector3(); let then = 0; function render(now) { now *= 0.001; deltaTime = now - then; then = now; if (resizeRendererToDisplaySize(renderer)) { const canvas = renderer.domElement; camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(); } // left, right, a, d const dx = ((keys[37] || keys[65]) ? 1 : 0) + ((keys[39] || keys[68]) ? -1 : 0); // up, down, w, s const dy = ((keys[38] || keys[87]) ? 1 : 0) + ((keys[40] || keys[83]) ? -1 : 0); const playerMoveSpeed = 10; // units per second camera.getWorldDirection(moveDir); moveDir.y = 0; // no up down movement moveDir.normalize(); // move player forward/back player.position.addScaledVector(moveDir, dy * playerMoveSpeed * deltaTime); // rotate direction 90 degrees const t = moveDir.x; moveDir.x = moveDir.z; moveDir.z = -t; // move player left/right player.position.addScaledVector(moveDir, dx * playerMoveSpeed * deltaTime); // if the cameraRig is too far from // player then move it const maxDistance = 6; const maxCamMoveSpeed = 0.015; const distance = cameraRig.position.distanceTo(player.position); if (distance > maxDistance) { const amount = maxCamMoveSpeed; cameraRig.position.lerp(player.position, amount); } camTarget.getWorldPosition(camTargetPos); camera.lookAt(camTargetPos); renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); window.addEventListener('keydown', (e) => { e.preventDefault(); keys[e.keyCode] = true; }); window.addEventListener('keyup', (e) => { e.preventDefault(); keys[e.keyCode] = false; }); } main();
 body { margin: 0; } #c { width: 100vw; height: 100vh; display: block; }
 <script src="https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.min.js"></script> <canvas id="c" tabindex="0"></canvas>

第三人稱相機可能很難。 上面那個太簡單了。 您可以將其想象為在玩家身后的繩子上拖動 cameraRig。 如果你備份相機不會移動。 它僅在相機距離 maxDistance 時移動。

通常將相機放在搖桿上,因此如果您向后走,搖桿會將相機推回。

 function main() { const canvas = document.querySelector('#c'); const renderer = new THREE.WebGLRenderer({canvas}); const keys = {}; const scene = new THREE.Scene(); const fov = 75; const aspect = 2; // the canvas default const near = 0.1; const far = 500; const camera = new THREE.PerspectiveCamera(fov, aspect, near, far); // put the camera 5 units above the rig const cameraRig = new THREE.Object3D(); cameraRig.add(camera); camera.position.y = 5; scene.add(cameraRig); cameraRig.position.z = 5; { const color = 0xFFFFFF; const intensity = 1; const light = new THREE.DirectionalLight(color, intensity); light.position.set(-1, 2, 4); scene.add(light); } { const size = 200; const divisions = 100; const gridHelper = new THREE.GridHelper(size, divisions); scene.add(gridHelper); } const boxWidth = 0.5; const boxHeight = 2; const boxDepth = 0.5; const geometry = new THREE.CylinderGeometry(boxWidth, boxDepth, boxHeight); const material = new THREE.MeshPhongMaterial({color:'red'}); const cube = new THREE.Mesh(geometry, material); const player = new THREE.Object3D(); const camTarget = new THREE.Object3D(); cube.position.y = boxHeight / 2; // move cube above ground player.add(cube); camTarget.position.y = boxHeight * 3 / 2; // target 2/3ds up the player player.add(camTarget); scene.add(player); function resizeRendererToDisplaySize(renderer) { const canvas = renderer.domElement; const width = canvas.clientWidth; const height = canvas.clientHeight; const needResize = canvas.width !== width || canvas.height !== height; if (needResize) { renderer.setSize(width, height, false); } return needResize; } const moveDir = new THREE.Vector3(); const camTargetPos = new THREE.Vector3(); const rigTargetPos = new THREE.Vector3(); function moveCameraToDistance(desiredDistance) { const maxCamMoveSpeed = 0.02; // delta from player to rig rigTargetPos.subVectors(cameraRig.position, player.position); // remove up/down rigTargetPos.y = 0; // no up/down // make unit vector rigTargetPos.normalize(); // make desiredDistance long rigTargetPos.multiplyScalar(desiredDistance); // add player position rigTargetPos.add(player.position); // move rig toward that position const curDistance = cameraRig.position.distanceTo(player.position); cameraRig.position.lerp( rigTargetPos, THREE.MathUtils.lerp( maxCamMoveSpeed, 1, THREE.MathUtils.clamp(1 - curDistance / desiredDistance, 0, 1))); } let then = 0; function render(now) { now *= 0.001; deltaTime = now - then; then = now; if (resizeRendererToDisplaySize(renderer)) { const canvas = renderer.domElement; camera.aspect = canvas.clientWidth / canvas.clientHeight; camera.updateProjectionMatrix(); } // left, right, a, d const dx = ((keys[37] || keys[65]) ? 1 : 0) + ((keys[39] || keys[68]) ? -1 : 0); // up, down, w, s const dy = ((keys[38] || keys[87]) ? 1 : 0) + ((keys[40] || keys[83]) ? -1 : 0); const playerMoveSpeed = 10; // units per second camera.getWorldDirection(moveDir); moveDir.y = 0; // no up down movement moveDir.normalize(); // move player forward/back player.position.addScaledVector(moveDir, dy * playerMoveSpeed * deltaTime); // rotate direction 90 degrees const t = moveDir.x; moveDir.x = moveDir.z; moveDir.z = -t; // move player left/right player.position.addScaledVector(moveDir, dx * playerMoveSpeed * deltaTime); // keep camera at distance const minDistance = 4; const maxDistance = 6; const distance = cameraRig.position.distanceTo(player.position); if (distance > maxDistance) { moveCameraToDistance(maxDistance); } else if (distance < minDistance) { moveCameraToDistance(minDistance); } // compute point from player in direction of rig // at desired distance camTarget.getWorldPosition(camTargetPos); camera.lookAt(camTargetPos); renderer.render(scene, camera); requestAnimationFrame(render); } requestAnimationFrame(render); window.addEventListener('keydown', (e) => { e.preventDefault(); keys[e.keyCode] = true; }); window.addEventListener('keyup', (e) => { e.preventDefault(); keys[e.keyCode] = false; }); } main();
 body { margin: 0; } #c { width: 100vw; height: 100vh; display: block; }
 <script src="https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.js"></script> <canvas id="c" tabindex="0"></canvas>

然后,您需要處理諸如在相機和播放器之間出現的東西之類的事情。 (有些游戲淡出這些東西)。 你還需要處理說穿過門。 有一段時間玩家將在門的一側,而攝像機在另一側(或者更確切地說是門口的兩側,所以攝像機會下降以便它可以透過門看到?牆壁會消失嗎?攝像機會跳嗎?穿過門並開始從其他一些位置看。傳聞是在馬里奧 64 中,一名程序員在相機上工作了整整一年,僅此而已。)

請注意,上面的某些代碼僅適用於someObject.position是世界空間位置的特殊情況(該對象沒有父對象,或者如果所有父對象都有 position = 0,0,0 rotation = 0,0 ,0, 比例 = 1,1,1)。 如果對象確實有父母,那么你需要獲得世界位置

const wp = new THREE.Vector3();
someObject.getWorldPosition(wp);

如果你想應用一個世界位置,你需要做更多的工作來使位置相對於父級。 現在,為了簡單起見,我只使用了世界位置就是它們的位置的對象。

暫無
暫無

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

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