管道漫游

1,181 阅读2分钟

整体思路

  1. 利用 CatmullRomCurve3 创建一个三维样条曲线
  2. 在三位样条曲线上等间距的取一系列点
  3. 相机位置按照第二步所取的移动。

实现步骤

三位样条曲线

import * as THREE from 'three';


// 三维样条曲线
const path = new THREE.CatmullRomCurve3([
    new THREE.Vector3(-50, 20, 90),
    new THREE.Vector3(-10, 40, 40),
    new THREE.Vector3(0, 0, 0),
    new THREE.Vector3(60, -60, 0),
    new THREE.Vector3(90, -40, 60),
    new THREE.Vector3(120, 30, 30),
]);

// 样条曲线path作为TubeGeometry参数生成管道
const geometry = new THREE.TubeGeometry(path, 200, 5, 30);

//纹理加载器
const texLoader = new THREE.TextureLoader(); 
const texture = texLoader.load('./diffuse.jpg');//纹理贴图

//UV坐标U方向阵列模式
texture.wrapS = THREE.RepeatWrapping;
//纹理沿着管道方向阵列数(UV坐标U方向)
texture.repeat.x = 10;

//材质对象
const material = new THREE.MeshLambertMaterial({
    map:texture, //纹理
    side: THREE.DoubleSide, //双面显示看到管道内壁
});

const mesh = new THREE.Mesh(geometry, material);

// 从曲线轨迹线上等间距获取一定数量点坐标
const pointsArr = path.getSpacedPoints(500);

export {mesh,pointsArr};

效果:

image.png

调整相机位置,让相机看向管道内部

核心代码:

const i = 100;
// 相机位置设置在当前点位置
camera.position.copy(pointsArr[i]);

// 曲线上当前点pointsArr[i]和下一个点pointsArr[i+1]近似模拟当前点曲线切线
// 设置相机观察点为当前点的下一个点,相机视线和当前点曲线切线重合
camera.lookAt(pointsArr[i + 1]);

效果展示:

image.png

注意点: 因为这里要模拟人眼效果,所以使用的是透视投影相机.

让相机动起来,实现一种漫游效果

**核心代码: **

// 渲染循环
let i = 0; //在渲染循环中累加变化
function render() {
    if (i < pointsArr.length - 1) {
        // 相机位置设置在当前点位置
        camera.position.copy(pointsArr[i]);
        // 曲线上当前点pointsArr[i]和下一个点pointsArr[i+1]近似模拟当前点曲线切线
        // 设置相机观察点为当前点的下一个点,相机视线和当前点曲线切线重合
        camera.lookAt(pointsArr[i + 1]);
        i += 1; //调节速度
    } else {
        i = 0
    }
    renderer.render(scene, camera);
    //请求动画帧,重复执行。
    requestAnimationFrame(render);
}

render();

效果:

8e41e0fb-9f0c-4e53-81e4-bb6ac3fd3142.gif

总结

管道漫游的本质也是移动相机位置,但需要注意一些细节问题,例如:

  • 如何让相机指向管道内部
  • 使用正投影相机还是使用透视投影相机
  • 相机位置改变的时候,相机lookAt 的改变

等等....