GLSL着色器为何将深色及亮色转换为绿色?
问题分析与修复方案
问题根源
你的代码里有三个关键问题导致了颜色异常:
- 错误的亮度计算:
dot(Color, vec3(1))只是把RGB三个通道的值加起来,这不是符合人眼感知的亮度(Luma)。正确的亮度需要根据RGB通道的视觉权重计算,比如BT.709标准的权重是红0.2126、绿0.7152、蓝0.0722。错误的亮度计算会让高/低亮度场景下的mix逻辑完全偏离预期。 - 除以0的精度风险:当颜色接近黑色时,
dot(Color, vec3(1.0))会趋近于0,直接做除法会引发数值溢出或精度崩溃,最终导致颜色偏绿(绿色通道数值相对突出时就会出现这种情况)。 - 极端参数的指数计算:如果
LumaMask过小或者Luma过高,-Luma * 2 * PI / LumaMask的绝对值会变得极大,exp的结果要么趋近于0要么趋近于1,mix操作会直接偏向某一端,放大计算误差。
修复后的代码
vec3 ExtractColor(vec3 Color, float LumaMask) { // 使用BT.709标准的亮度权重计算真实Luma const vec3 lumaWeights = vec3(0.2126, 0.7152, 0.0722); float Luma = dot(Color, lumaWeights); // 钳制LumaMask避免极端值,防止指数计算溢出 LumaMask = max(LumaMask, 0.001); float ColorMask = exp(-Luma * 2.0 * PI / LumaMask); Color = mix(Color, vec3(Luma), ColorMask); // 加入极小epsilon避免除以0,同时完成归一化 float sum = dot(Color, vec3(1.0)); return Color / max(sum, 0.0001); }
关键修改说明
- 替换亮度计算权重:用标准的视觉权重计算Luma,确保亮度值符合人眼感知,让mix逻辑的色彩过渡更自然。
- 钳制LumaMask:给
LumaMask设置最小阈值,避免指数函数的参数出现极端值,稳定ColorMask的输出范围。 - 安全归一化:给归一化的分母加一个极小的
epsilon(0.0001),彻底避免除以0的情况,防止数值异常。
内容的提问来源于stack exchange,提问作者Summit
相关产品推荐
相关产品推荐

