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

如何让THREE.js中陡峭平面的凸起部分比低洼部分更暗?

问题分析与解决方案

你的核心问题在于片元着色器的颜色计算逻辑完全偏离了“基于高度控制明暗”的目标——原代码用屏幕坐标gl_FragCoord除以顶点传递的test向量,这种计算没有任何物理意义,导致颜色出现异常的强对比度。

下面提供两种简单可行的调整方案,都能实现“低洼更暗、凸起更亮”的自然效果,且对比度可控:


方案一:直接基于高度值映射颜色

这种方法最直观,直接用顶点的z高度值来控制颜色亮度,通过调整映射范围就能控制对比度。

修改后的顶点着色器

varying float vHeight; // 只传递高度值到片元着色器

void main(void) {
    float amp = 2.5;
    float z = amp * sin(position.x*0.2) * cos(position.y*0.5);
    vHeight = z; // 传递高度值

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

修改后的片元着色器

precision mediump float;
varying float vHeight;

void main(void) {
    // 先把高度值归一化到[0,1]范围:z的最小值是-2.5,最大值是2.5
    float normalizedHeight = (vHeight + 2.5) / 5.0;
    // 调整对比度:用pow函数,指数>1会降低暗部亮度,指数<1会提亮暗部
    float brightness = pow(normalizedHeight, 1.2); // 指数可根据需求调整,比如1.0是线性映射
    // 生成灰度颜色,也可以改成彩色,比如vec3(brightness, 0.5, 1.0 - brightness)
    gl_FragColor = vec4(vec3(brightness), 1.0);
}

调整技巧:

  • 如果觉得暗部太亮,增大pow的指数(比如1.5、2.0)
  • 如果觉得亮部太暗,减小指数(比如0.8、0.9)
  • 也可以用smoothstep(0.0, 1.0, normalizedHeight)来替代pow,实现更柔和的过渡

方案二:用漫反射光照实现自然明暗

这种方法更接近真实光照效果,通过计算平面的法向量,模拟光源照射产生的明暗,对比度和过渡更自然。

修改后的顶点着色器

varying vec3 vNormal; // 传递法向量到片元着色器
varying vec3 vPosition; // 传递世界空间位置

void main(void) {
    float amp = 2.5;
    float z = amp * sin(position.x*0.2) * cos(position.y*0.5);
    vec3 pos = vec3(position.x, position.y, z);

    // 计算法向量(基于高度场的数值微分)
    float delta = 0.1; // 采样步长
    float z1 = amp * sin((position.x + delta)*0.2) * cos(position.y*0.5);
    float z2 = amp * sin(position.x*0.2) * cos((position.y + delta)*0.5);
    vec3 tangent = vec3(delta, 0.0, z1 - z);
    vec3 bitangent = vec3(0.0, delta, z2 - z);
    vNormal = normalize(cross(tangent, bitangent));

    vPosition = pos;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}

修改后的片元着色器

precision mediump float;
varying vec3 vNormal;
varying vec3 vPosition;

void main(void) {
    // 定义光源方向(世界空间)
    vec3 lightDir = normalize(vec3(1.0, 1.0, 2.0));
    // 计算漫反射强度
    float diff = max(dot(vNormal, lightDir), 0.0);
    // 基础颜色 + 漫反射亮度,可调整基础色和强度
    vec3 color = vec3(0.6, 0.8, 1.0) * (0.3 + diff * 0.7); // 0.3是环境光强度,0.7是漫反射权重
    gl_FragColor = vec4(color, 1.0);
}

调整技巧:

  • 调整lightDir可以改变光源方向,影响明暗分布
  • 修改0.3(环境光)和0.7(漫反射权重)可以控制整体对比度:环境光越大,暗部越亮,对比度越低;反之则对比度越高
  • 替换vec3(0.6, 0.8, 1.0)可以改变平面的基础颜色

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 17:10:31