threejs 自学 关于摄像机的使用

2023-03-29  本文已影响0人  squidbrother

摄像机运动的理解

观察一个模型的方式

  1. 保持摄像机不变情况下,通过修改被观察模型的旋转角度、位置、大小,来实现;
  2. 旋转摄像机的情况下,通过轨道控制器Orbit controls,实现摄像机的变化
  3. 不借助于轨道控制器,通过脚本来旋转摄像机 - (更加灵活,最重要一点,不需要人为操作)

基本使用

  1. 三维图查看角度
// 通过UI按钮改变相机观察角度
document.getElementById('x').addEventListener('click', function () {
    camera.position.set(500, 0, 0); //x轴方向观察
    camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
// 通过UI按钮改变相机观察角度
document.getElementById('y').addEventListener('click', function () {
    camera.position.set(0, 500, 0); //y轴方向观察
    camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
// 通过UI按钮改变相机观察角度
document.getElementById('z').addEventListener('click', function () {
    camera.position.set(0, 0, 500); //z轴方向观察
    camera.lookAt(0, 0, 0); //重新计算相机视线方向
})
  1. 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();
  1. 镜头的基本运动
    模拟 贯穿 整个街道的镜头效果
    模拟 望远镜放大缩小( 最好使用目标与摄像机的距离,作为边界显示 )
// 渲染循环
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();

实际使用

  1. 操控摄像机围绕模型旋转
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();
}
  1. 将移动镜头封装为一个函数,并且增加缓动效果
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 });
});
  1. 摄像机沿着指定轨迹漫游
    示例地址 - http://www.webgl3d.cn/pages/188907/

  2. 操作摄像机与模型互动,如 开门进入车内动画

  1. 当小人模型移动到某个指定区域范围时候,修改摄像机的位置以及朝向
//-- 检测修改摄像机位置函数
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 );
}
  1. 模型沿着指定轨迹行驶,渲染时候切换三个摄像机镜头 -- (既有轨迹运动也有镜头切换,推荐!)

OrbitControls轨道控制器 与 摄像机的关系

执行构造函数THREE.OrbitControls()浏览器会同时干两件事,
给浏览器定义了一个鼠标、键盘事件,自动检测鼠标键盘的变化,如果变化了就会自动更新相机的数据, 执行该构造函数同时会返回一个对象
给该对象添加一个监听事件,只要鼠标或键盘发生了变化,就会触发渲染函数

作者:3D建模学习
链接:https://juejin.cn/post/7221777883160510525
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

轨道控制器与摄像机的关系 轨道控制器与摄像机的关系2
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 );

} );

未完待续.....

上一篇下一篇

猜你喜欢

热点阅读