Skip to content

38. 实战:林海雪原(二)

Published:

上节我们完成了林海雪原的场景。

但有一个问题:

image.png

这个山坡其实是有高低起伏的,但现在看不出来,都是白色的。

能不能给山坡根据不同的高度来设置不同颜色呢?

可以的。

用前面学过的自定义顶点颜色 geometry.attributes.color 的知识。

我们可以拿到所有顶点的坐标,也就是就可以拿到每个顶点的高度,根据高度来设置这个顶点的颜色就好了。

改下 mountainside.js

image.png

const heightArr = [];
for (let i = 0; i < positions.count; i++) {
    heightArr.push(positions.getZ(i));
}
heightArr.sort();

const minHeight = heightArr[0];
const maxHeight = heightArr[heightArr.length - 1];
const height = maxHeight - minHeight;

const colorsArr = [];
const color1 = new THREE.Color('green');
const color2 = new THREE.Color('red');

for (let i = 0; i < positions.count; i++) {
    const percent = (positions.getZ(i) - minHeight) / height;
    const c = color1.clone().lerp(color2, percent);
    colorsArr.push(c.r, c.g, c.b); 
}
const colors = new Float32Array(colorsArr);
geometry.attributes.color = new THREE.BufferAttribute(colors, 3);

const material = new THREE.MeshLambertMaterial({
    // color: new THREE.Color('white'),
    vertexColors:true,
    // wireframe: true
});

因为旋转之前这个山坡是在 XY 平面的,也就是 Z 坐标是高度。

我们拿到所有顶点的 Z,排一下序。

计算出最低和最高的高度,高度差就是山坡的整体高度。

然后遍历每个顶点,用当前高度减去最低高度,算出百分比,这样就可以实现颜色插值。

用 color.lerp 方法,指定一个开始颜色、一个结束颜色,然后根据高度算出百分比之后,就可以算出这个百分比对应的颜色。

把算出的 colors 数组设置到 geometry.attributes.color。

然后材质里开启 vertextColors 为 true,使用顶点颜色。

这样,就实现了顶点颜色的自定义,并且自定义的颜色是和高度相关的。

看下效果:

2025-04-04 21.41.07.gif

可以明显看出来,海拔高的地方是红色,海拔低的地方时绿色,中间高度是渐变的颜色。

然后我们设置山顶白色,山谷灰色就好了:

image.png

const color1 = new THREE.Color('#eee');
const color2 = new THREE.Color('white');

2025-04-04 21.44.59.gif

现在,海拔高低就一目了然了。

对比之前的:

image.png

是不是好多了?

然后我们加一个相机动画,这里让相机做圆周运动:

image.png

let angle = 0;
let r = 1000;
function render() {
    angle += 0.03;

    camera.position.x = r * Math.cos(angle);
    camera.position.z = r * Math.sin(angle);

    camera.lookAt(0, 0, 0);

    renderer.render(scene, camera);
    requestAnimationFrame(render);
}

每一帧改变相机的位置,设置半径为 1000,每一帧改变一下角度,用 cos、sin 算出当前的 x、z 来,然后 lookAt 0,0,0

看下效果:

2025-04-04 22.02.48.gif

案例代码上传了小册仓库

总结

这节我们做了一些优化。

通过自定义顶点颜色实现了海拔高度的区分,拿到所有顶点坐标,根据高度用 color.lerp 计算颜色插值,实现了不同高度的顶点颜色不同。

之后又加上了相机的圆周动画,根据角度的 cos、sin 计算相机位置的 x、z,高度 y 保持不变。

这个实战里自定义顶点坐标、自定义顶点颜色都用到了,这些原理性的东西还是很重要的。

评论