You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用顶点着色器根据高度为起伏平面着色?

问题:Three.js地形高度分层着色异常(整体偏蓝)

我使用Three.js的Mesh、PlaneGeometry和ShaderMaterial创建了带起伏效果的平面,尝试通过顶点着色器根据平面高度给地形分层着色(顶部、中部用不同颜色),但最终效果几乎全为蓝色。

我的尝试代码

顶点着色器

varying vec3 vColor;

void main(void) {
    float uAmp = 20.0;

    float z = uAmp * sin(position.x*0.7) * cos(position.y*0.7);

    gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, z, 1.0);

    if (gl_Position.z <= 2.0*uAmp/3.0) {
        vColor = vec3(1.0, 0.0, 0.0);
    }
    else if (gl_Position.z <= 2.0*uAmp*(2.0/3.0)) {
        vColor = vec3(0.0, 1.0, 0.0);
    }
    else {
        vColor = vec3(0.0, 0.0, 1.0);
    }
}

片元着色器

precision mediump float;

varying vec3 vColor;

void main(void) {   
    gl_FragColor = vec4(vColor, 1.0);
}

错误原因

  1. 误用裁剪空间坐标判断高度:gl_Position是经过投影变换后的裁剪空间坐标,其z值范围为[-1,1],和原始地形高度z不是同一维度的数值,用它来判断高度完全无效。
  2. 条件逻辑重复:第一个判断条件<=2.0*uAmp/3.0和第二个<=2.0*uAmp*(2.0/3.0)是同一个数值(≈13.3),导致第二个条件永远不会触发;再加上gl_Position.z远小于这个值,所有顶点都会进入else分支,显示蓝色。

修正方案

改用原始计算的地形高度z来判断区间,同时修正条件逻辑:

修正后的顶点着色器

varying vec3 vColor;

void main(void) {
    float uAmp = 20.0;
    // 计算原始地形高度(范围:[-20,20])
    float z = uAmp * sin(position.x*0.7) * cos(position.y*0.7);
    
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position.x, position.y, z, 1.0);

    // 根据原始高度z分层着色
    float heightThreshold1 = uAmp * 0.66;
    float heightThreshold2 = uAmp * 0.33;
    float heightThreshold3 = -uAmp * 0.33;
    float heightThreshold4 = -uAmp * 0.66;

    if (z >= heightThreshold1) {
        vColor = vec3(0.0, 0.0, 1.0); // 顶部蓝色
    } else if (z >= heightThreshold2) {
        vColor = vec3(0.0, 1.0, 0.0); // 中部绿色
    } else if (z >= heightThreshold3) {
        vColor = vec3(1.0, 1.0, 0.0); // 中间黄色
    } else if (z >= heightThreshold4) {
        vColor = vec3(1.0, 0.0, 0.0); // 下部红色
    } else {
        vColor = vec3(0.5, 0.0, 0.5); // 底部紫色
    }
}

片元着色器(无需修改)

precision mediump float;
varying vec3 vColor;

void main(void) {   
    gl_FragColor = vec4(vColor, 1.0);
}

补充说明

  • 原始地形高度z的范围是[-uAmp, uAmp](因为sin和cos的乘积范围为[-1,1]),所以判断区间要对应这个范围设置。
  • 如果需要更平滑的颜色过渡,可以改用mix()函数实现颜色插值,避免生硬的区间切换。

内容的提问来源于stack exchange,提问作者Jonas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:20:33