如何使用顶点着色器根据高度为起伏平面着色?
问题: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); }
错误原因
- 误用裁剪空间坐标判断高度:
gl_Position是经过投影变换后的裁剪空间坐标,其z值范围为[-1,1],和原始地形高度z不是同一维度的数值,用它来判断高度完全无效。 - 条件逻辑重复:第一个判断条件
<=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
相关产品推荐
相关产品推荐

