前言
在网上找的相机过渡代码,不是代码有问题,就是建议写死轨迹坐标来进行移动,而我想要的是移动到目标坐标后,能正面朝向目标模型,并且能调整相机朝向目标模型的角度。最后靠着以前做 Canvas 积累的三角函数的知识终于实现了这个功能。
准备工作
- 下载 tween.js 用于实现过渡的效果
- 想要复习三角函数的可以看看这个网站 www.shuxuele.com/sine-cosine…
问题描述
经过测试相机移动到目标坐标是没有问题的,问题是出在相机看向的目标角度不对,相机不能正面朝向目标模型。效果如下图所示
功能实现
- 公式:
- Math.PI / 2 = 弧度,弧度换算成角度 = 90度角。
- X = Math.cos(Math.PI / 2) * 间隔距离 + 目标坐标
- Y = Math.sin(Math.PI / 2) * 间隔距离 + 目标坐标
其实不使用 Math.PI / 2 也能实现看向90度角的效果,这样也就意味着不能自己设置想看向的其他角度。
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<div id="WebGl-output"></div>
<script src="libs/three.js"></script>
<script src="libs/OrbitControls.js"></script>
<script src="libs/tween.js"></script>
<script>
let scene = new THREE.Scene()
let camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
let renderer = new THREE.WebGLRenderer()
renderer.setClearColor(0x000000);
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
let axes = new THREE.AxesHelper(20)
scene.add(axes)
let planeGeometry = new THREE.PlaneGeometry(60, 20, 1, 1)
let planeMatrices = new THREE.MeshLambertMaterial({color: 0xAAAAAA})
let plane = new THREE.Mesh(planeGeometry, planeMatrices)
plane.position.set(15, 0, 0)
plane.rotation.set(-0.5 * Math.PI, 0, 0)
plane.receiveShadow = true
scene.add(plane)
let cubeGeometry = new THREE.BoxGeometry(4, 4, 4)
let cubeMatrices = new THREE.MeshLambertMaterial({
color: 0xff0000,
})
let cube = new THREE.Mesh(cubeGeometry, cubeMatrices)
cube.castShadow = true
cube.position.set(-4, 3, 0)
scene.add(cube)
let sphereGeometry = new THREE.SphereGeometry(4, 20, 20)
let sphereMatrices = new THREE.MeshLambertMaterial({
color: 0x7777ff,
})
let sphere = new THREE.Mesh(sphereGeometry, sphereMatrices)
sphere.position.set(20, 4, 2)
sphere.castShadow = true
scene.add(sphere)
let spotLight = new THREE.SpotLight(0xffffff)
spotLight.position.set(-40, 40, -15)
spotLight.castShadow = true
spotLight.shadow.mapSize = new THREE.Vector2(1024, 1024);
spotLight.shadow.camera.far = 130;
spotLight.shadow.camera.near = 40;
scene.add(spotLight)
camera.position.set(-30, 40, 30)
camera.lookAt(scene.position)
let ambient = new THREE.AmbientLight(0x353535);
scene.add(ambient);
document.getElementById('WebGl-output').append(renderer.domElement)
let controls = new THREE.OrbitControls(camera, renderer.domElement)
controls.target = new THREE.Vector3(0, 0, 0)
const raycaster = new THREE.Raycaster()
let mouse = new THREE.Vector2()
let intersects = null
renderer.domElement.addEventListener('click', function (event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
intersects = raycaster.intersectObject(scene, true);
if (intersects.length > 0) {
let boxMaxY = new THREE.Box3().setFromObject(intersects[0].object).max.y
let distance = boxMaxY + 10
let angel = Math.PI / 5
let position = {
x: intersects[0].object.position.x + Math.cos(angel) * distance,
y: intersects[0].object.position.y,
z: intersects[0].object.position.z + Math.sin(angel) * distance
}
let tween = new TWEEN.Tween(camera.position).to(position, 3000)
let tween1 = new TWEEN.Tween(controls.target).to(intersects[0].object.position, 3000)
controls.enabled = false;
tween.onComplete(function () {
controls.enabled = true;
})
tween.start()
tween1.start()
}
});
function render() {
requestAnimationFrame(render)
TWEEN.update()
controls.update()
renderer.render(scene, camera)
}
render()
</script>
</body>
</html>
复制代码