简体   繁体   English

Three.js OrbitControls 绕环旋转

[英]Three.js OrbitControls Rotating Around a ring

I have an OrbitControls camera which rotates around the dot: target = player.position.x, y and z.我有一个围绕点旋转的 OrbitControls 相机:target = player.position.x, y and z。 It's pretty ok, but the player is right in the centre of the screen.这很好,但玩家就在屏幕中央。 I need a camera to rotate around a ring... first picture: target is in the centre, second: target is always placed to the left of the centre我需要一个相机围绕一个环旋转......第一张图片:目标在中心,第二张:目标总是放在中心的左边

Let me explain: Here is my code:让我解释一下:这是我的代码:

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

So we rotate around a fixed dot.所以我们围绕一个固定的点旋转。

But I need a dot which changes its position depending on controls.getAzimuthalAngle() or something else.但我需要一个点,它根据 control.getAzimuthalAngle() 或其他东西改变其位置。 The camera must be like in GTA V or other games, where a player is not right in the centre of the screen, but a little to the left, so it's more convenient for, for example, aiming, the player does not interfere with the aim in the centre.相机必须像 GTA V 或其他游戏中一样,玩家不在屏幕中央,而是向左一点,这样更方便,例如瞄准,玩家不会干扰瞄准中心。

Help...帮助...

Generally for a 3rd person camera you constantly target the camera at the player (or some offset from the player, or some object attached to the player)通常对于第三人称相机,您会不断将相机对准玩家(或与玩家的一些偏移,或连接到玩家的某些物体)

You then have the camera follow the player over time.然后你让相机随着时间的推移跟随玩家。

In the code below there is a cameraRig that follows the player.在下面的代码中,有一个跟随玩家的cameraRig The camera rig is there so we don't have to do any math to keep the camera above the ground.相机装备就在那里,所以我们不需要做任何数学运算来保持相机高于地面。 Similarly there is a camTarget which is attached to the player.类似地,还有一个附加到播放器的camTarget This is so the camera looks at about shoulder height.这就是相机看起来与肩同高的原因。

 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>

3rd person cameras can be hard.第三人称相机可能很难。 The one above is too simple.上面那个太简单了。 You can think of it as if the cameraRig is being dragged on a string behind the player.您可以将其想象为在玩家身后的绳子上拖动 cameraRig。 If you back up the camera doesn't move.如果你备份相机不会移动。 It only moves if the the camera is maxDistance away.它仅在相机距离 maxDistance 时移动。

It's common to instead put the camera on a stick so if you walk backward the stick pushed the camera back.通常将相机放在摇杆上,因此如果您向后走,摇杆会将相机推回。

 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>

You then need to deal with things like stuff getting between the camera and the player.然后,您需要处理诸如在相机和播放器之间出现的东西之类的事情。 (some games fade that stuff out). (有些游戏淡出这些东西)。 You also need to deal with say walking through a door.你还需要处理说穿过门。 For a while player will be on one side of the door and the camera on the other (or rather opposite sides of the doorway so does the camera come down so it can see through the door? Does the wall fade out? Does the camera jump through the door and start looking from some other positions. Rumor is in Mario 64 one programmer worked on the camera an entire year and nothing else.)有一段时间玩家将在门的一侧,而摄像机在另一侧(或者更确切地说是门口的两侧,所以摄像机会下降以便它可以透过门看到?墙壁会消失吗?摄像机会跳吗?穿过门并开始从其他一些位置看。传闻是在马里奥 64 中,一名程序员在相机上工作了整整一年,仅此而已。)

Note that some of the code above only works in the special case that someObject.position is a world space postion (the object has no parent objects, or if it does all the parents have position = 0,0,0 rotation = 0,0,0, scale = 1,1,1).请注意,上面的某些代码仅适用于someObject.position是世界空间位置的特殊情况(该对象没有父对象,或者如果所有父对象都有 position = 0,0,0 rotation = 0,0 ,0, 比例 = 1,1,1)。 If the object does have parents then you'd need to get the world position with如果对象确实有父母,那么你需要获得世界位置

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

And if you wanted to apply a world position you'd need to do more work to make the position relative of the parent.如果你想应用一个世界位置,你需要做更多的工作来使位置相对于父级。 For now, to keep it simple, I just used objects who's world position is their position.现在,为了简单起见,我只使用了世界位置就是它们的位置的对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM