本章主要学习知识点
- 学习如何实现曲线颜色渐变
- 掌握利用插值实现颜色渐变
- 学会查看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,
})
}
})
});

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