首页 > 解决方案 > Three.js - 与父级分开旋转相机

问题描述

我有一个场景,其中对象围绕CatmullRomCurve3路径移动,按或箭头键时向左移动,按或left箭头down键时向右移动。rightup

我最初有一个问题,我希望对象与路径成 90 度而不是沿着路径面对。你可以在那里找到我的这个场景的代码。这个问题已经用这个答案解决了。

基本上,我所要做的就是实现以下代码来旋转对象:

object.lookAt((p2).sub(p1).applyAxisAngle(axis, -Math.PI * 0.5).add(p1));

虽然对象现在可以正确旋转,但我现在遇到的问题是它camera没有面向与对象相同的方向或与对象一起移动(我想要对象的肩上型透视),但有人建议我解决这个问题将相机添加为对象的子对象,这很有效!

新问题

我现在希望对象的默认位置与路径成 90 度角(原样),但是当您按下leftdown箭头时,我希望对象面朝左(沿着原来的路径返回),并面向当按rightup箭头时,反之。

我设法通过if在循环中设置一些语句来使其工作,这些语句根据按下的键render将值更改-Math.PI * 0.5为任一-Math.PI * 2-Math.PI * 0.5左右。

但是,这也会导致相机采用该新lookAt值,因为它是对象的子对象,但我希望相机始终保持在同一位置(即与路径成 90 度角,就像对象在静止时所做的那样)。

那么,当对象发生变化时,如何阻止相机旋转/移动/更改它lookAt(我不确定它是哪一个)?

似乎我对相机所做的一切都不会影响它,它总是锁定到对象的相同方向。

提前致谢。

标签: javascriptthree.js

解决方案


我希望我已经正确理解了你的问题:

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 20, -20);
camera.lookAt(0, 0, 0);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var grid = new THREE.GridHelper(300, 30);
grid.position.setZ(100);
scene.add(grid);

var points = [
  new THREE.Vector3(-80, 5, 35),
  new THREE.Vector3(-80, 5, 192.5),
  new THREE.Vector3(80, 5, 192.5),
  new THREE.Vector3(80, 5, 35)
];

var curve = new THREE.CatmullRomCurve3(points);
curve.closed = true;

var curvePoints = curve.getPoints(200);
var geomCurvePath = new THREE.BufferGeometry().setFromPoints(curvePoints);
var matCurvePath = new THREE.LineBasicMaterial({
  color: 0xff0000
});
var CurvePath = new THREE.Line(geomCurvePath, matCurvePath);
scene.add(CurvePath);

var group = new THREE.Group();
scene.add(group);

group.add(camera);

var pointerGeom = new THREE.ConeGeometry(4, 20, 4);
pointerGeom.translate(0, 10, 0);
pointerGeom.rotateX(Math.PI * 0.5);
var pointer = new THREE.Mesh(pointerGeom, new THREE.MeshNormalMaterial());
group.add(pointer);

btnLeft.addEventListener("click", function() {
  turn(Math.PI * 0.5)
});
btnRight.addEventListener("click", function() {
  turn(-Math.PI * 0.5)
});

function turn(angle) {
  pointer.rotation.y += angle;
}

var p1 = new THREE.Vector3();
var p2 = new THREE.Vector3();
var lookAt = new THREE.Vector3();
var axis = new THREE.Vector3(0, 1, 0);
var percentage = 0;

render();

function render() {
  requestAnimationFrame(render);
  percentage += 0.0005;
  curve.getPointAt(percentage % 1, p1);
  curve.getPointAt((percentage + 0.001) % 1, p2);
  lookAt.copy(p2).sub(p1).applyAxisAngle(axis, -Math.PI * 0.5).add(p1); // look at the point 90 deg from the path
  group.position.copy(p1);
  group.lookAt(lookAt);
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}

#buttons {
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/92/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></script>
<div id="buttons">
  <button id="btnLeft">left</button>
  <button id="btnRight">right</button>
</div>


推荐阅读