Three.js-硬要自学系列19 (曲线颜色渐变、渐变插值、查看设置gltf顶点、山脉高度可视化)

本章主要学习知识点

  • 学习如何实现曲线颜色渐变
  • 掌握利用插值实现颜色渐变
  • 学会查看gltf顶点并设置其顶点
  • 练习山脉高度可视化

曲线颜色渐变

「曲线颜色渐变」可以理解为让一条3D曲线从起点到终点呈现颜色逐渐变化的效果,就像用不同颜色的彩笔依次涂满线条的不同段落。

创建一条曲线,获取曲线上的点

js 复制代码
const geometry = new THREE.BufferGeometry();
const curve = new THREE.CatmullRomCurve3([
    new THREE.Vector3( -10, 0, 0 ),
    new THREE.Vector3( -5, 5, 0 ),
    new THREE.Vector3( 0, 0, 0 ),
    new THREE.Vector3( 5, -5, 0 ),
    new THREE.Vector3( 10, 0, 0 ),
])
// 曲线取点
const pointsArr = curve.getSpacedPoints( 120 );
// 设置顶点位置
geometry.setFromPoints( pointsArr );

计算每个顶点的颜色

js 复制代码
const pos = geometry.attributes.position;
const count = pos.count;  // 顶点数量
const colorsArr = [];
for ( let i = 0; i < count; i ++ ) {
    //点索引值相对所有点数量的百分比
    const percent = i / count;
    const color = new THREE.Color();
    color.setHSL( percent, 1.0, 0.5 );
    colorsArr.push( color.r, color.g, color.b );
}
const colors = new Float32Array( colorsArr );
// 设置颜色属性
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

const material = new THREE.LineBasicMaterial( {
     vertexColors: true  // 使用顶点颜色
    } );
const line = new THREE.Line( geometry, material );

scene.add( line );

颜色渐变插值

颜色渐变插值,可以理解为让颜色在三维模型的顶点之间自动平滑过渡,这个过程就像给模型的不同部位涂上不同颜色,而Three.js 会自动混合中间区域的颜色。

顶点颜色驱动

每个3D模型的几何体由多个顶点组成。如果你给不同顶点设置不同颜色,Three.js 在渲染时会自动计算顶点之间的颜色过渡,形成渐变效果

创建一组顶点

js 复制代码
const geometry = new THREE.BufferGeometry();    
const vertices = new Float32Array([
    0, 0, 0,
    5, 0, 0,
    5, 5, 0,
    0, 5, 0,
])
// 定义索引数据
const indexes = new Uint16Array([
  0,1,2,
  0,2,3
])
// 设置几何体顶点索引数据
geometry.setIndex(new THREE.BufferAttribute(indexes,1))
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3))

通过lerp插值计算颜色

js 复制代码
const pos = geometry.attributes.position;
const count = pos.count;
const c1 = new THREE.Color(1, 2, 0)
const c2 = new THREE.Color(0, 1, 1)
const colorsArr = [];
console.log(count);

for (let i = 0; i < count; i++) {
    // 计算百分比
    const percent = i / count;
    // 根据百分比插值计算颜色
    const c = c1.clone().lerp(c2, percent)
    // 将颜色值添加到数组中
    colorsArr.push(c.r, c.g, c.b)
}
geometry.setAttribute('color', new THREE.BufferAttribute(new Float32Array(colorsArr), 3))

查看设置gltf顶点

通过使用GLTFLoader导入模型,遍历所有子对象,attributes.position获取模型的顶点,设置顶点坐标

js 复制代码
const loader = new GLTFLoader(loadingManager);
loader.load('model/free_gmc_motorhome_reimagined_low_poly/scene.glb', function (gltf) {
    scene.add(gltf.scene);

    // 遍历gltf场景中的所有子对象
    gltf.scene.traverse(function (child) {
        if (child.isMesh) {
            // 获取顶点数量
            const pos = child.geometry.attributes.position;
            const count = pos.count;
            // 获取顶点索引
            const index = child.geometry.index;

            for( let i = 0; i < count; i++){
                // 获取pos对象中第i个元素的y坐标
                const y = pos.getY(i);
                // 将pos对象中第i个元素的y坐标乘以2
                pos.setY(i, y * 2);
            }   
        }
    })  
})

山脉高度可视化

js 复制代码
   const loader = new GLTFLoader(loadingManager);
    loader.load( 'model/mountain_terrain2.glb', function ( gltf ) {    
        scene.add( gltf.scene );
        gltf.scene.traverse((child) => {
            if (child.isMesh) {
                const mesh = child;
                const pos = mesh.geometry.attributes.position;
                const count = pos.count;
                
                 // 计算模型y坐标高度差
                const yArr = [];
                for(let i = 0; i < count; i++) {
                    yArr.push(pos.getY(i))
                }
                // 高度排序
                yArr.sort(); // 从小到大排序
                
                const minY = yArr[0];
                const maxY = yArr[yArr.length - 1];
                const height = maxY - minY; // 山脉整体高度
    

                const colorsArr = [];
                const c1 = new THREE.Color(0x00ff00);
                const c2 = new THREE.Color(0xff0000);
                for(let i = 0; i < count; i++) {
                    // 计算当前位置的百分比
                    const percent = (pos.getY(i) - minY) / height;
                    
                    // 根据百分比计算颜色
                    const color = c1.clone().lerp(c2, percent);
                    
                    // 将颜色添加到颜色数组中
                    colorsArr.push(color.r, color.g, color.b);
                }

                const colors = new Float32Array(colorsArr);
                mesh.geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

                mesh.material = new THREE.MeshLambertMaterial({
                    vertexColors: true,
                })

            }
        })
    });

以上案例均可在案例中心查看体验

THREE 案例中心

相关推荐
FungLeo19 分钟前
node 后端和浏览器前端,有关 RSA 非对称加密的完整实践, 前后端匹配的代码演示
前端·非对称加密·rsa 加密·node 后端
不灭锦鲤29 分钟前
xss-labs靶场第11-14关基础详解
前端·xss
不是吧这都有重名1 小时前
利用systemd启动部署在服务器上的web应用
运维·服务器·前端
霸王蟹1 小时前
React中巧妙使用异步组件Suspense优化页面性能。
前端·笔记·学习·react.js·前端框架
Maỿbe1 小时前
利用html制作简历网页和求职信息网页
前端·html
森叶1 小时前
Electron 主进程中使用Worker来创建不同间隔的定时器实现过程
前端·javascript·electron
霸王蟹2 小时前
React 19 中的useRef得到了进一步加强。
前端·javascript·笔记·学习·react.js·ts
霸王蟹2 小时前
React 19版本refs也支持清理函数了。
前端·javascript·笔记·react.js·前端框架·ts
繁依Fanyi2 小时前
ColorAid —— 一个面向设计师的色盲模拟工具开发记
开发语言·前端·vue.js·编辑器·codebuddy首席试玩官
明似水3 小时前
Flutter 开发入门:从一个简单的计数器应用开始
前端·javascript·flutter