深入URP之Shader篇7: SimpleLit Shader分析(3)
创始人
2024-03-24 01:47:15
0

Simple Lit Forward Pass

Fragment shader 函数

上篇中分析了Simple Lit Forward Pass的Vertex Shader都计算和输出了什么数据,本篇就看看在Fragment shader中是怎么使用这些数据计算最终的光照颜色的。
由于代码较短,就都贴出来方便查看:

half4 LitPassFragmentSimple(Varyings input) : SV_Target
{UNITY_SETUP_INSTANCE_ID(input);UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);float2 uv = input.uv;half4 diffuseAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap));half3 diffuse = diffuseAlpha.rgb * _BaseColor.rgb;half alpha = diffuseAlpha.a * _BaseColor.a;AlphaDiscard(alpha, _Cutoff);#ifdef _ALPHAPREMULTIPLY_ONdiffuse *= alpha;#endifhalf3 normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap));half3 emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap));half4 specular = SampleSpecularSmoothness(uv, alpha, _SpecColor, TEXTURE2D_ARGS(_SpecGlossMap, sampler_SpecGlossMap));half smoothness = specular.a;InputData inputData;InitializeInputData(input, normalTS, inputData);half4 color = UniversalFragmentBlinnPhong(inputData, diffuse, specular, smoothness, emission, alpha);color.rgb = MixFog(color.rgb, inputData.fogCoord);color.a = OutputAlpha(color.a, _Surface);return color;
}

首先进行的是Alpha Test

之前在分析Depth Only Pass的时候就看过alpha test的处理,和这儿有些类似,但是由于Depth only pass更加通用,所以会在使用albedo贴图alpha的时候做一些判断,在某些情况下这个贴图的alpha是不用来做alpha test的(贴图的alpha通道存储的是smoothness, glossiness这样的值),因此就不使用它作为alpha test的参数。而Simple Lit这儿就简单了,因为这个shader里面不使用那些关键字对应的功能,因此也无需判断那些关键字。
注意这儿采样贴图使用的函数名是SampleAlbedoAlpha,这个函数之前已经看过,就是使用SAMPLE_TEXTURE2D采样一张2D贴图,采样出来的结果是一个half4。你可以理解为这个half4包含了rgb反射率(albedo)和alpha。即不是简单的将贴图中的texel看成是一个颜色。diffuseAlpha.rgb_BaseColor.rgb相乘作为最终的diffuse系数(其实仍然是反射率),而diffuseAlpha.a_BaseColor.a相乘得到最终的alpha,使用AlphaDiscard函数进行Alpha Test。

void AlphaDiscard(real alpha, real cutoff, real offset = 0.0h)
{#ifdef _ALPHATEST_ONclip(alpha - cutoff + offset);#endif
}

最终调用的是hlsl的clip函数,clip函数当接受的参数值小于0时丢弃这个片段。这儿的offset一般都不会设置,就是0,可以忽略,而alpha和cutoff比较,如果alpha < cutoff则片段没通过alpha test被丢弃。所以cutoff设置的是可通过alpha test的最小的alpha值,大于或等于cutoff的alpha值是通过alpha test的。

预乘alpha

还记得一开始我们看unlit shader的属性时说的BaseShaderGUI吗?预乘alpha开启的条件其实就是blend mode为Premultiply:

                    case BlendMode.Premultiply:material.SetInt("_SrcBlend", (int) UnityEngine.Rendering.BlendMode.One);material.SetInt("_DstBlend", (int) UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);material.EnableKeyword("_ALPHAPREMULTIPLY_ON");

此时,srcBlend为one,而dstBlend为1-srcAlpha,即blend的公式为:

finalColor = srcColor + (1-srcAlpha)*dstColor

和标准的alpha blend模式相比,srcColor在混合时不需要再乘以alpha,因为alpha已经预先乘上去了:

#ifdef _ALPHAPREMULTIPLY_ONdiffuse *= alpha;
#endif

这两种做法有何区别?很显然,这儿只有diffuse使用了alpha,而如果在blend时使用alpha是对最终颜色乘以alpha,所以这种做法得到的颜色应该更亮一些。因为可以认为乘alpha是减淡颜色。再多说一句预乘alpha这个技术,早期经常用在2d游戏渲染半透明sprite,在载入sprite时即预乘alpha(或是在导入资源时处理sprite图片),这样在渲染时就可以少一个乘法,性能提高了而效果是一样的,当然了这种做法时alpha值是不能变的,不能做fade in/fade out。

采样法线贴图

half3 normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap));

SampleNormal函数如下:

half3 SampleNormal(float2 uv, TEXTURE2D_PARAM(bumpMap, sampler_bumpMap), half scale = 1.0h)
{
#ifdef _NORMALMAPhalf4 n = SAMPLE_TEXTURE2D(bumpMap, sampler_bumpMap, uv);#if BUMP_SCALE_NOT_SUPPORTEDreturn UnpackNormal(n);#elsereturn UnpackNormalScale(n, scale);#endif
#elsereturn half3(0.0h, 0.0h, 1.0h);
#endif
}

如果定义了相应的关键字,则采样法线贴图,且根据是否使用了bump scale,使用不同的解码函数。这两个unpcak函数在SRP Core的Packing.hlsl中,涉及到法线贴图相关的编码方式,这儿不细说,也许会有一篇单独分析法线贴图会说。一般来说,法线贴图会保存切线空间的法线,因此这儿的变量名为normalTS

采样自发光贴图

half3 emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap));
half3 SampleEmission(float2 uv, half3 emissionColor, TEXTURE2D_PARAM(emissionMap, sampler_emissionMap))
{
#ifndef _EMISSIONreturn 0;
#elsereturn SAMPLE_TEXTURE2D(emissionMap, sampler_emissionMap, uv).rgb * emissionColor;
#endif
}

就是采样一张自发光贴图再乘以一个自发光颜色。

采样高光贴图以及获取smoothness

half4 specular = SampleSpecularSmoothness(uv, alpha, _SpecColor, TEXTURE2D_ARGS(_SpecGlossMap, sampler_SpecGlossMap));
half smoothness = specular.a;

SampleSpecularSmoothness函数在SimpleLitInput.hlsl中:

TEXTURE2D(_SpecGlossMap);       SAMPLER(sampler_SpecGlossMap);half4 SampleSpecularSmoothness(half2 uv, half alpha, half4 specColor, TEXTURE2D_PARAM(specMap, sampler_specMap))
{half4 specularSmoothness = half4(0.0h, 0.0h, 0.0h, 1.0h);
#ifdef _SPECGLOSSMAPspecularSmoothness = SAMPLE_TEXTURE2D(specMap, sampler_specMap, uv) * specColor;
#elif defined(_SPECULAR_COLOR)specularSmoothness = specColor;
#endif#ifdef _GLOSSINESS_FROM_BASE_ALPHAspecularSmoothness.a = exp2(10 * alpha + 1);
#elsespecularSmoothness.a = exp2(10 * specularSmoothness.a + 1);
#endifreturn specularSmoothness;
}

根据不同的关键字,从高光贴图中采样出高光颜色或者直接使用材质定义的高光色。注意这儿的_GLOSSINESS_FROM_BASE_ALPHA,前面alpha test那儿说过,这个关键字表示base贴图的alpha存储的是glossiness,否则就使用高光贴图的alpha作为glossiness使用。这儿使用exp2解码smoothness,说明贴图中存储的是log空间。

待续

后面还有两篇讲这个Fragment Shader,这个Shader虽然不复杂,光照计算也只是传统的BlinnPhong,但是涉及到非常多的Unity光照系统的东西以及URP的惯例用法,所以内容较多,咱们慢慢来。

相关内容

热门资讯

求救:<<永恒之星... 求救:<<永恒之星>>黑屏进不了,弹出个对话框是否VISTA系统啊?是的话要用兼容模式(98)运行是...
为什么许多人拍视频都求点赞呢?... 为什么许多人拍视频都求点赞呢?点赞能赚钱吗?点赞并不能赚钱,但是会获得平台给的流量。把你的粉丝数达到...
5万左右买什么二手车好? 5万左右买什么二手车好?买车最主要的是看用途了,如果你商用什么的当然要大点的,帕萨特03年的市场价也...
新武林外传战场武器有哪些?分别... 新武林外传战场武器有哪些?分别什么属性武林外传战场武器有哪些?叫什么名字?有些什么属性?百分比攻击的...
十二生肖中无腥不吃的动物是??... 十二生肖中无腥不吃的动物是???如果有猫就好了
红宝石通关后的攻略 红宝石通关后的攻略从吉纳镇向东冲浪(天柱位于131号水道)上到2层发现地面有裂缝,激吵需用风马自行车...
求对对子的大佬给我这副对联整个... 求对对子的大佬给我这副对联整个横批上联:腰持管理裙装照片下联:颈佩周年纪念金银求个横批上联是:腰持管...
魔法禁书目录现在还在更新吗? 魔法禁书目录现在还在更新吗?那动画现在出到哪儿了啊?魔法禁书目录第一季和ova已完结,第二季还在连载...
庄子中的一个小故事,我忘了原文... 庄子中的一个小故事,我忘了原文,谁来帮忙回忆你都明白其中的意思了要什么出处啊。嘿嘿,我不知道,来开个...
看过韩剧《新娘18岁》的人谁知... 看过韩剧《新娘18岁》的人谁知道什么叫宗孙啊?这部电视剧很好看,可是一面的宗孙什么意思 一直困扰着我...
东西方礼仪教育差异?请大家帮帮... 东西方礼仪教育差异?请大家帮帮忙!东方在孩子从小到大的教育中把礼仪归结为礼貌,只有家庭教育中涉及到,...
高中生物哪一部分最难 高中生物哪一部分最难遗传是较难的,会涉及到计算不知道你所在的是什么区域,课本不同分为人教版和大纲版总...
请问宜宾江北哪有学画画的,在书... 请问宜宾江北哪有学画画的,在书香府邸附近更好找你美术老师书香府第就有的安,还附近……好像以前学院里面...
有一首歌忘记了,只记住一句是(... 有一首歌忘记了,只记住一句是(喝最烈的酒)分手了还是朋友作词:龙军 作曲:龙军演唱:程响躲在无人的角...
求伤感的纯音乐 求伤感的纯音乐去搜索班得瑞的,不错,好听情海 -- sara翅膀 --林依晨错得人 --萧亚轩仍然 ...
小小忍者日番谷冬狮郎外套、乌尔... 小小忍者日番谷冬狮郎外套、乌尔奇奥拉外套和蝎外套用哪个好?我是雷国的,还有它们的配招还有用哪种的装备...
木匠 面对乡村这种景象,为什么... 木匠 面对乡村这种景象,为什么我却回到这儿(1)对家园的坚守,这儿承载着我的生活,有我熟悉的人和事。...
中脉周希俭有怎么的创业历程? 中脉周希俭有怎么的创业历程?周希俭他的创业历程是非常的艰难的,而且他有特别好的运气。创业历程,我爱你...
的说说短语:我每天都在笑,但过... 的说说短语:我每天都在笑,但过得好不好只有自己知道这句话还是有道理的笑是给别人看的人都有藏短的习惯不...
女生说我话少我该怎么办? 女生说我话少我该怎么办?女生说你说话比较少,可能是因为你的性格内向,或者说你没有找到感兴趣的话题,你...