问题
The idea is to have a square room in which an object (and the camera a little further back to be able to view the object - i.e. over the shoulder camera) moves around from corner to corner, facing the walls at all times but curving smoothly round, so that when transitioning from one wall to the other, the object (and camera) are not exactly 90 degrees perpendicular, but transition from 90 degrees perpendicular with one wall, to 90 degrees perpendicular with the next.
How I went about it
My solution to this was to create a CatmullRomCurve3
from an array of 4 sets of coordinates (4 corners) and then have the object and camera animate along this curve. I have got this to work successfully with the code below, but my problem is that the object and camera are both looking at (lookAt
) the path in front of them. I like that the angle of the object and camera constantly change to match the angle of the path, and I basically want to offset this by 90 degrees (I think?), so that they still move in the same way, but lookAt
the wall.
So basically, what I want:
- Object and camera moving along the path in the same way, but offset their
rotation
/lookAt
so that they are always facing a wall/corner and not in front of them. - Right now I understand how to offset the camera slightly behind the object to give an over shoulder perspective, but I imagine this would change with the object facing the walls as the camera then needs to be behind the object on a different axis, so an explanation for this would be great too.
My Code to create the curve
var curve;
function createCurvePath() {
//Array of points
var points = [
[-80, 5, 35],
[-80, 5, 192.5],
[80, 5, 192.5],
[80, 5, 35]
];
//Convert the array of points into vertices
for (var i = 0; i < points.length; i++) {
var x = points[i][0];
var y = points[i][1];
var z = points[i][2];
points[i] = new THREE.Vector3(x, y, z);
}
//Create a closed curve
curve = new THREE.CatmullRomCurve3(points);
curve.closed = true;
var points = curve.getPoints( 200 );
var geomCurvePath = new THREE.BufferGeometry().setFromPoints( points );
var matCurvePath = new THREE.LineBasicMaterial( { color : 0xff0000 } );
// Create the final object to add to the scene
var CurvePath = new THREE.Line( geomCurvePath, matCurvePath );
scene.add(CurvePath);
}
Code to animate (render loop)
// loop that runs every frame to render scene and camera
function render(){
requestAnimationFrame(render);
// Move camera along path
percentage += 0.0005;
var p1 = curve.getPointAt(percentage % 1);
var p2 = curve.getPointAt((percentage + 0.01) % 1);
camera.position.set(p1.x, p1.y, p1.z);
object.position.set(p1.x, p1.y, p1.z);
camera.lookAt(p2);
object.lookAt(p2);
renderer.render(scene, camera);
}
回答1:
Just an option, use .applyAxisAngle()
method:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(0, 100, 300);
var renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
var controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target = new THREE.Vector3(0, 5, 100);
controls.update();
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 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());
scene.add(pointer);
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
pointer.position.copy(p1);
pointer.lookAt(lookAt);
renderer.render(scene, camera);
}
body {
overflow: hidden;
margin: 0;
}
<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>
来源:https://stackoverflow.com/questions/50019038/three-js-object-lookat-90-degrees-perpendicular-from-path-its-travelling-on