08_颜色锐化处理

颜色锐化处理

获取遮蔽信息

pixelNDotL,含贴图法线发兰伯特拥有很多细节 NDotL,顶点法线的兰伯特非常光滑细节较少

NDotL - pixelNDotL,两者相减可以得到物体的凹凸信息,那么用1减去这个值就可以得到一个遮罩的遮蔽信息occlusion

遮蔽信息调整

1 -  (NDotL - pixelNDotL) 当前遮蔽信息还是不够强烈所以先乘上3在用1减去,这样增强效果,这里乘以几都可以,可以随意调整,以效果为主,最后进行钳制防止有小于零的值 saturate((1 - 3 * (NDotL - pixelNDotL))) occlusion的杂色太多了,所以整体提亮2倍,去除一些杂色,只保留较小的信息,这里乘几同样也是经验值类的,自己随意调整以效果为准 (saturate((1 - 3 * (NDotL - pixelNDotL))) * 2 这里进行了occlusion乘上他的平方根,这样写不太好理解作用,它等价于pow(occlusion,1.5)。那么pow的作用就增加对比度,亮度更亮暗的更暗,最后在钳制防止超过1 最后计算获得一个颜色衰减值,兰伯特的值是-1~1,这里使用半兰伯特0~1和遮罩系数进行计算是为了保留教暗地方的依旧有颜色衰减值,我们默认使用的是兰伯特光照,所以这里进行混合,使用0.5也就是均匀混合。这样就得到了一个颜色的衰减值,注意这里说的衰减值是作用于Gamma矫正也就是颜色变化,而不是仅仅亮度变化,这里叫做颜色Gamma矫正衰减系数应该比较合适

Gamma矫正

颜色钳制

有了颜色Gamma矫正衰减系数,然后知道Gamma矫正的值后,就可以对颜色进行Gamma矫正了,但在这之前需要钳制颜色亮度,因为Gamma其实本质可以理解为Pow(Color,gamma),对于大于1的进行Pow会导致变得非常亮 这里函数内部对颜色各个分量取得最大值,如果大于1,就将整个颜色除以这个值进行压暗,保证颜色不变的情况下降低明度,钳制到1以下

计算颜色亮度和gamma值

这里Luminance()函数是根据权重计算颜色的灰度(亮度)值。最终通过灰度值来控制Gmma值基数,使用颜色Gamma矫正衰减系数混合,这里这个乘 0.2875和加1.4375的操作也属于经验值,并不是固定的,以效果为准

Luminance()函数在UnityCG.cginc中 Unity的颜色权重宏定义 Luminance()函数原型 默认的SRGB权重 现在有了Gama值后,现在就进行颜色的Gamma矫正了。直接使用pow即可,钳制一下不要等于0了,根据效果来调整强度,使用兰伯特控制,亮的部分就使用Gamma,暗的地方就减小Gamma强使用GammaHalf 完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//颜色调整
float3 gammaColor = matCapColor;
{
    float pixelNDotL = dot(pixelNormalWS, lightDirectionWS);
    float NDotL = dot(normalWS, lightDirectionWS); 
    float occlusion = saturate(1 - 3 * (NDotL - pixelNDotL)) * 2;
    occlusion *= sqrt(occlusion);
    //occlusion = pow(occlusion, 1.5);
    occlusion = min(1, occlusion);
	//颜色Gamma矫正衰减系数
	float attenuation = lerp((pixelNDotL * 0.5 + 0.5) * occlusion, saturate(pixelNDotL), 0.5);
    //钳制亮度
    float3 matCapColorClamped = ClampColorMax(matCapColor);
    //颜色转单一亮度
    float luminance = Luminance(matCapColor);
    //计算gamma值
    float gamma = lerp(luminance * 0.2875 + 1.4375, 1, attenuation);
    //颜色进行Gamma
    float3 matCapColorGamma = pow(max(1e-5, matCapColorClamped), gamma); 
    //Gamma效果削弱
    float3 matCapColorGammaHalf = lerp(matCapColor, matCapColorGamma, 0.5);
    //均衡Gamma效果
    gammaColor = lerp(matCapColorGammaHalf, matCapColorGamma, saturate(NDotL));
}

当前效果

左边是无处理,右边是映射了的 可以看出处理过之后颜色变化更明显了


Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • URP - RendererFeature :ScreenSpaceOutline
  • 平滑法线处理 - 八面体映射
  • Lv.3 Unity主线:一个简单的PBRShader
  • 理论支线:直接光漫反射与GGX高光的混合问题
  • 理论支线:PBR - 基于图像的照明( image based lighting-IBL)
  • # #