April 4, 2025

Shader - ColorOffset


// fragment.glsl
uniform vec3 uDepthColor;
uniform vec3 uSurfaceColor;
uniform float uColorOffset;
uniform float uColorMultiplier;

varying float vElevation;

void main() {

    // 數值差 取名 offset / bias , 倍數差 取名 multiplier / scale
    float mixStrength = (vElevation + uColorOffset) * uColorMultiplier;

    // mix 0~1 兩個顏色過渡, 由 vElevation 控制混合比例
    vec3 color = mix(uDepthColor, uSurfaceColor, mixStrength);
    gl_FragColor = vec4(color, 1.0);
    #include <colorspace_fragment>

    /**
    #include <colorspace_fragment> 主要是為了 確保顏色輸出符合 WebGL / Three.js 的色彩空間設定。
    建議加上,避免顏色偏暗或顯示不正確。
    如果你的渲染結果是直接給貼圖 (texture) 或特殊用途,可能可以省略。
    */
}

clipboard.png

GLSL 顏色混合與 mixStrength 計算解析

1. vElevation 是什麼?

2. uColorOffset 是什麼?

(vElevation + uColorOffset)

範例

vElevationuColorOffset = 0.2vElevation + uColorOffset
0.00.20.2
0.50.20.7
1.00.21.2

這讓顏色過渡往移動了。

3. uColorMultiplier 是什麼?

(vElevation + uColorOffset) * uColorMultiplier

範例

vElevation + uColorOffsetuColorMultiplier = 2.0mixStrength
0.02.00.0
0.52.01.0
1.02.02.0

在這個例子中,mixStrength 變成 [0, 2],超出了 mix 的標準 [0,1] 範圍,這可能會導致顏色過渡超過 uSurfaceColor,甚至變成 uSurfaceColor 之外的顏色。

4. 這行公式的作用

整體來說:

float mixStrength = (vElevation + uColorOffset) * uColorMultiplier;

5. 為什麼要這樣設計?

這樣的設計比單純 mix(uDepthColor, uSurfaceColor, vElevation) 更靈活:

  1. 可以調整顏色過渡開始的高度(uColorOffset → 讓顏色變化區間更自由。

  2. 可以控制顏色變化的速率(uColorMultiplier → 讓顏色變化更平滑或更劇烈。

  3. 允許 mixStrength 超過 [0,1],創造更多可能性 → 可以讓 mix 產生額外的顏色效果,例如 vElevation 超過 1.0 可能導致額外的高亮區域。

6. mixStrength 超過 [0,1] 會怎樣?

GLSL 的 mix(x, y, a) 允許 a 超過 1.0 或低於 0.0,這時候會進行線性外推(extrapolation)。

如果你希望 mixStrength 始終在 [0,1] 之間,可以用 clamp() 限制:

mixStrength = clamp(mixStrength, 0.0, 1.0);

這樣就能確保顏色變化不會超過原本的範圍。

7. 總結

這行程式碼:

float mixStrength = (vElevation + uColorOffset) * uColorMultiplier;

這是用於 地形、流體、火焰、雲層等漸變色 效果的常見技術!🔥🎨