摄像机运动的理解
观察一个模型的方式
- 保持摄像机不变情况下,通过修改被观察模型的旋转角度、位置、大小,来实现;
- 旋转摄像机的情况下,通过轨道控制器Orbit controls,实现摄像机的变化
- 不借助于轨道控制器,通过脚本来旋转摄像机 - (更加灵活,最重要一点,不需要人为操作)
基本使用
- 三维图查看角度
- x轴方向观察
// 通过UI按钮改变相机观察角度
document.getElementById('x').addEventListener('click', function () {
camera.position.set(500, 0, 0); //x轴方向观察
camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
- y轴方向观察
// 通过UI按钮改变相机观察角度
document.getElementById('y').addEventListener('click', function () {
camera.position.set(0, 500, 0); //y轴方向观察
camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
- z轴方向观察
// 通过UI按钮改变相机观察角度
document.getElementById('z').addEventListener('click', function () {
camera.position.set(0, 0, 500); //z轴方向观察
camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
- lookAt()的作用
改变.position属性后,如果不执行.lookAt()方法,相机的观察方向默认不变
如果你希望相机圆周运动的同时,改变相机视线方向,保持相机镜头始终指向坐标原点或其它位置,需要每次改变.position属性后,重新执行一遍.lookAt()方法
function render() {
angle += 0.01;
camera.position.x = R * Math.cos(angle);
camera.position.z = R * Math.sin(angle);
// .position改变,重新执行lookAt(0,0,0)计算相机视线方向
camera.lookAt(0,0,0);
requestAnimationFrame(render);
}
render();
- 镜头的基本运动
模拟 贯穿 整个街道的镜头效果
模拟 望远镜放大缩小( 最好使用目标与摄像机的距离,作为边界显示 )
// 渲染循环
function render() {
camera.position.z -= 0.3; //-- 相机逐步向canvas画布内移动(如果目标的z值 比摄像机的z值 小的话)
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
// 渲染循环
function render() {
camera.position.z += 0.3; //-- 相机逐步向canvas画布外移动(如果目标的z值 比摄像机的z值 大的话)
renderer.render(scene, camera);
requestAnimationFrame(render);
}
render();
实际使用
- 操控摄像机围绕模型旋转
- 参考案例链接:
https://threejs.org/examples/webgl_interactive_cubes.html
let theta = 0;
init();
animate();
function init(){
let camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
}
function animate(){
requestAnimationFrame( animate );
render();
}
function render(){
theta += 0.1;
camera.position.x = radius * Math.sin( THREE.MathUtils.degToRad( theta ) );
camera.position.y = radius * Math.sin( THREE.MathUtils.degToRad( theta ) );
camera.position.z = radius * Math.cos( THREE.MathUtils.degToRad( theta ) );
camera.lookAt( scene.position );
camera.updateMatrixWorld();
}
- 将移动镜头封装为一个函数,并且增加缓动效果
- 参考案例链接:
https://dragonir.github.io/3d/#/shadow
- 光、模型与摄像机
import { TWEEN } from 'three/examples/jsm/libs/tween.module.min.js';
...
function animateCamera(position, rotation) {
//相机 - 位置动画
new TWEEN.Tween(camera.position)
.to(position, 1800)
.easing(TWEEN.Easing.Quadratic.InOut)
.start()
.onComplete(function () {
TWEEN.remove(this)
})
//相机 - 旋转动画
new TWEEN.Tween(camera.rotation)
.to(rotation, 1800)
.easing(TWEEN.Easing.Quadratic.InOut)
.start()
.onComplete(function () {
TWEEN.remove(this)
})
}
// 点击第一Tab菜单
document.getElementById('one').addEventListener('click', () => {
document.getElementById('one').classList.add('active');
document.getElementById('two').classList.remove('active')
document.getElementById('content').innerHTML = 一段文字'
animateCamera({ x: 3.2, y: 2.8, z: 3.2 }, { y: 1 });
});
摄像机沿着指定轨迹漫游
示例地址 -http://www.webgl3d.cn/pages/188907/
操作摄像机与模型互动,如 开门进入车内动画
- 操作摄像机移动到指定位置
示例地址 -https://juejin.cn/post/7028780379649605646
- 当小人模型移动到某个指定区域范围时候,修改摄像机的位置以及朝向
//-- 检测修改摄像机位置函数
function checkChangeCameraFn(roleObject){
//-- 当前摄像机的位置
var camPos = new THREE.Vector3(
camera.position.x,
camera.position.y,
camera.position.z
);
//-- 目标摄像机的位置
var targetPos;
//-- 角色进入指定范围
if ( rolePosition.position.x > -3 && rolePosition.position.x < 22 && rolePosition.position.z > 31 && roleObject.position.z < 58 ) {
targetPos = new THREE.Vector3(
roleObject.position.x,
roleObject.position.y + 50,
roleObject.position.z + 40
);
}else{
//-- 角色不在指定范围内,摄像机位置回到之前与角色关系位置
targetPos = new THREE.Vector3(
roleObject.position.x,
roleObject.position.y + 30,
roleObject.position.z + 60
);
}
//-- 通过Vector3的lerp方法,实现当前位置与目标位置的缓动动画
camPos.lerp(targetPos, 0.033);
//-- 修改摄像机的位置以及朝向
camera.position.copy(camPos);
camera.lookAt(ballPosition.position);
}
animate();
function animate(){
requestAnimationFrame( animate );
...
//-- 摄像机位置朝向改变
checkChangeCameraFn(小人模型对象);
renderer.render( scene, camera );
}
- 模型沿着指定轨迹行驶,渲染时候切换三个摄像机镜头 -- (既有轨迹运动也有镜头切换,推荐!)
- 添加若干相机,如全局相机,模型相机,被模型盯住模型上的相机,切换相机来显示
- 沿着指定轨迹行驶
原贴地址 -https://juejin.cn/post/7061203887536996360
OrbitControls轨道控制器 与 摄像机的关系
- 说明:
OrbitControls轨道控制器,是一个threejs的非核心库,无需安装,只要显示引入js文件即可
执行构造函数THREE.OrbitControls()浏览器会同时干两件事,
给浏览器定义了一个鼠标、键盘事件,自动检测鼠标键盘的变化,如果变化了就会自动更新相机的数据, 执行该构造函数同时会返回一个对象
给该对象添加一个监听事件,只要鼠标或键盘发生了变化,就会触发渲染函数
作者:3D建模学习
链接:https://juejin.cn/post/7221777883160510525
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 轨道控制器与摄像机的关系
※ OrbitControls.target属性对应目标 等同于 camera.lookAt()的观察目标
※ OrbitControls.update(); 等同于 相机控件内部会执行 camera.lookAt(controls.target);
※ 对于透视投影相机而言,OrbitControls缩放,本质上就是改变camera.position
- 轨道控制器常用属性和方法
controls.enablePan = false; //禁止右键拖拽
controls.enableRotate = false; //禁止旋转
controls.enableZoom = false;//禁止缩放
controls.minDistance = 200; //相机位置与观察目标点最小值
controls.maxDistance = 500; //相机位置与观察目标点最大值
controls.getDistance(); //计算出camera.position和controls.target的距离
- 限制摄像机的旋转范围
默认上下旋转范围:
// 上下旋转范围
controls.minPolarAngle = 0; //-- 默认值0
controls.maxPolarAngle = Math.PI; //-- 默认值Math.PI
限制不能看到模型底部
controls.maxPolarAngle = Math.PI/2;
限制左右范围 - 如: 前方180度内
controls.minAzimuthAngle = -Math.PI/2;
controls.maxAzimuthAngle = Math.PI/2;
- 借助轨道控制器查看摄像机的位置变化
orbitControl.addEventListener( 'change', function () {
//相机位置与目标观察点距离
// const pos = camera.position;
// console.log( 'pos', pos );
// const dis = orbitControl.getDistance();
// console.log( 'dis', dis );
} );
未完待续.....