深入URP之Shader篇3: Unlit Shader分析[下]

这篇具有很好参考价值的文章主要介绍了深入URP之Shader篇3: Unlit Shader分析[下]。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Unlit shader

上篇中我们分析了Unlit shader的Properties在ShaderGUI中的处理,接下来看Sub Shader。

SubShader

unlit shader以及其他URP shader包含两个SubShader,分别是针对ShaderModel4.5和2.0。由于unlit shader本身很简单,这两个SubShader几乎一样,唯一的差别是ShaderModel 4.5的SubShader会定义#pragma multi_compile _ DOTS_INSTANCING_ON,这个可参考dots-instancing-shaders,本文中先忽略它。总之这儿的要点是URP会针对比较强大的设备使用一个SubShader,而比较弱的设备使用另一个。但这并不是说URP只是把设备分成两类这么简单,这儿只说Shader。由于硬件总是要发展,我们关注的重点是ShaderModel4.5,因此就只看这第一个SubShader了。

Pass

我们看到unlit shader的SubShader中包含了3个Pass,分别是Unlit,DepthOnlyMeta。我们知道URP是单Pass渲染,这只是说URP是在一个Pass中完成物体的大部分计算,包含各种光照的计算等等。而Sub Shader中仍然是会包含多个pass,这些Pass是在渲染管线中特定的时候被执行。例如这儿的DepthOnlypass,是在渲染所有不透明物体之前预先生成一张depth texture的pass;而Metapass则只在烘焙光照贴图时使用。而决定这些pass被使用的并不是他们的名字,而是上面说过的LightModetag。但是Unlitpass并没有指定这个tag,所以它使用的就是默认的SRPDefaultUnlit

unlit pass

首先分析unlit pass

  • keyword定义:
            #pragma shader_feature_local_fragment _ALPHATEST_ON
            #pragma shader_feature_local_fragment _ALPHAPREMULTIPLY_ON

            // -------------------------------------
            // Unity defined keywords
            #pragma multi_compile_fog
            #pragma multi_compile_instancing
            #pragma multi_compile _ DOTS_INSTANCING_ON

shader feature支持alpha test和 alpha premultiply,muti compile则包含fog, instacing和 dots instancing。这些都是一些宏定义开关,shader使用了不同的开关,会编译成不同的变体,变体才是最终使用的shader。对于shader feature是可以定义在材质上的,上面处理Properties的时候看到会根据不同情况设置不同的关键字,就是设置使用这儿的关键字,所以要首先包含这些关键字。而multi compile是指无论如何都要包含这些关键字(和材质是否开启没关系)。

  • uniform定义:
    uniform定义被包含在文件 UnlitInput.hlsl 中。这个hlsl文件定义了unlit shader使用的uniform,根据SRP的规则,使用的是CBuffer。
CBUFFER_START(UnityPerMaterial)
    float4 _BaseMap_ST;
    half4 _BaseColor;
    half _Cutoff;
    half _Surface;
CBUFFER_END

CBUFFER_STARTCBUFFER_END是定义在SRP Core的Shader Library中的宏,并且根据不同的API有不同的定义,在GLES2中由于不支持constant uniform buffer,因此这两个宏被定义为空。

  • Attributes 和 Varyings
    这两个分别是vertex shader的输入,以及fragment shader的输入,这是URP的命名习惯,和内置流水线不一样。
            struct Attributes
            {
                float4 positionOS       : POSITION;
                float2 uv               : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct Varyings
            {
                float2 uv        : TEXCOORD0;
                float fogCoord  : TEXCOORD1;
                float4 vertex : SV_POSITION;

                UNITY_VERTEX_INPUT_INSTANCE_ID
                UNITY_VERTEX_OUTPUT_STEREO
            };

先忽略gpu instancing相关的宏。vs的输入只有位置和uv坐标,而fs的输入还多了一个fogCoord。

  • Vertex shader
            Varyings vert(Attributes input)
            {
                Varyings output = (Varyings)0;

                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_TRANSFER_INSTANCE_ID(input, output);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.vertex = vertexInput.positionCS;
                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
                output.fogCoord = ComputeFogFactor(vertexInput.positionCS.z);

                return output;
            }

同样先忽略instacing。VS就是简单的从物体局部坐标系变换到clip space,将结果写入Varying的vertex;变换uv坐标;以及计算雾参数。
这儿要注意的是GetVertexPositionInputs方法。这个方法位于Packages\com.unity.render-pipelines.universal\ShaderLibrary\ShaderVariablesFunctions.hlsl中:

VertexPositionInputs GetVertexPositionInputs(float3 positionOS)
{
    VertexPositionInputs input;
    input.positionWS = TransformObjectToWorld(positionOS);
    input.positionVS = TransformWorldToView(input.positionWS);
    input.positionCS = TransformWorldToHClip(input.positionWS);

    float4 ndc = input.positionCS * 0.5f;
    input.positionNDC.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
    input.positionNDC.zw = input.positionCS.zw;

    return input;
}

可以看到,这个方法里面计算了世界坐标,view坐标和clip space坐标,以及NDC坐标。几乎所有的URP shader都会调用这个方法。虽然说unlit shader里面只需要clip space坐标,但是为了统一就直接调用了。由于shader的函数都是内联的,不使用的变量和方法应该会被编译器优化掉(错了请告诉我),所以也不用太担心性能浪费。
关于uv坐标的变换,使用了TRANSFORM_TEX这个宏,这个宏的定义位于SRP Core的Shader Library中:
#define TRANSFORM_TEX(tex, name) ((tex.xy) * name##_ST.xy + name##_ST.zw)
就是使用_BaseMap_ST去缩放偏移了一下uv坐标。
最后,ComputeFogFactor也位于ShaderVariablesFunctions.hlsl中:

real ComputeFogFactor(float z)
{
    float clipZ_01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(z);

    #if defined(FOG_LINEAR)
        // factor = (end-z)/(end-start) = z * (-1/(end-start)) + (end/(end-start))
        float fogFactor = saturate(clipZ_01 * unity_FogParams.z + unity_FogParams.w);
        return real(fogFactor);
    #elif defined(FOG_EXP) || defined(FOG_EXP2)
        // factor = exp(-(density*z)^2)
        // -density * z computed at vertex
        return real(unity_FogParams.x * clipZ_01);
    #else
        return 0.0h;
    #endif
}

首先,real是一个宏定义,位于SRP Core的Common.hlsl中,对于支持half的平台,real就是half,否则就是float。
UNITY_Z_0_FAR_FROM_CLIPSPACE是定义在URP的core.hlsl中的一个宏,会根据是否是reverse Z做不同的计算,关于z相关的话题是很重要也比较复杂的,将会单独写一篇,这儿就不说了。

  • Fragment Shader
            half4 frag(Varyings input) : SV_Target
            {
                UNITY_SETUP_INSTANCE_ID(input);
                UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

                half2 uv = input.uv;
                half4 texColor = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv);
                half3 color = texColor.rgb * _BaseColor.rgb;
                half alpha = texColor.a * _BaseColor.a;
                AlphaDiscard(alpha, _Cutoff);

#ifdef _ALPHAPREMULTIPLY_ON
                color *= alpha;
#endif

                color = MixFog(color, input.fogCoord);

                return half4(color, alpha);
            }

SAMPLE_TEXTURE2D是一个定义在SRP Core shader library中的一个跨平台的宏,例如:
dx11是
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) textureName.Sample(samplerName, coord2)

GLES2是
#define SAMPLE_TEXTURE2D(textureName, samplerName, coord2) tex2D(textureName, coord2)

AlphaDiscard也还是位于ShaderVariablesFunctions.hlsl中:
void AlphaDiscard(real alpha, real cutoff, real offset = 0.0h)
{
#ifdef _ALPHATEST_ON
clip(alpha - cutoff + offset);
#endif
}
很简单,根据是否定义_ALPHATEST_ON关键字,使用cutoff计算clip。
这儿还会判断关键字_ALPHAPREMULTIPLY_ON,如果定义,则会将alpha值预先乘到color上,这就是传统的Alpha预乘技术。

Depth only pass

Depth only pass用于生成场景的深度贴图。这个pass的代码在Packages\com.unity.render-pipelines.universal\Shaders\DepthOnlyPass.hlsl中。

本篇小结

本篇中我们主要分析了Unlit pass的内容,可以看到很多宏定义,函数都来自于URP和SRP Core的ShaderLibrary中。熟悉这些宏和函数方便我们写自己的自定义Shader。另外我们要注意CBuffer这个结构,后面会说一下SRP Batcher相关的内容。文章来源地址https://www.toymoban.com/news/detail-495946.html

到了这里,关于深入URP之Shader篇3: Unlit Shader分析[下]的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Unity Shader 学习(一):初识ShaderLab -- 以“Unlit Shader”模板为例 01

    阅读本文前需要对 渲染流程 有简单了解,并且要知道 Unity ShaderLab、Cg/HLSL 大概是什么,它们并不是一回事。 然后, 看什么教程都不如直接看官方文档: ShaderLab - Unity手册 HLSL参考 首先创建一个 Unlit Shader 模板(Project 窗口,右键 → Create → Shader → Unlit Shader) 直接上代码:

    2024年02月03日
    浏览(40)
  • Unity中Shader URP 简介

    在这篇文章中,我们主要介绍一下Unity中的URP(通用渲染管线)是什么 Unity帮助文档 Windows and UWP Mac and IOS Android Xbox One PlayStation4 Nintendo Switch WebGL All current VR platforms 在Unity2018以前,Unity使用的一直都是Build-in Render Pipeline(内置渲染管线) 在早期使用内置渲染管线时,Unity为了适配

    2024年01月16日
    浏览(63)
  • Unity URP Shader(HLSL)踩坑日记(一)

    最近开始转TA,刚开始学习,资料比较杂乱,其中遇到的问题和一些计算方式,记录一下,后续会一直完善补充。 注意此时Properties中的属性,如果要开启SRP合批,需要放到CBUFFER代码块中。 应用阶段准备的数据---- 顶点着色处理数据(返回值为处理后的数据)---- ------ 片元着色器

    2024年01月17日
    浏览(44)
  • Unity Shader从内置渲染管线迁移到URP

    Unity 在URP中将shader更新为了HLSL语言,使用build-in shader 无法直接在URP中使用 这里讲一下关于shader的更新方法 参考 From Built-in to URP Tags 添加 \\\"RenderPipeline\\\" = \\\"UniversalPipeline\\\" CGPROGRAM ENDCG 改变为 HLSLPROGRAM ENDHLSL #include \\\"UnityCG.cginc\\\" 更改为 #include \\\"Packages/com.unity.render-pipelines.universal/Sh

    2024年02月05日
    浏览(47)
  • Unity 性能优化之Shader分析处理函数ShaderUtil.HasProceduralInstancing: 深入解析与实用案例

    点击封面跳转到Unity国际版下载页面 在Unity中,性能优化是游戏开发过程中非常重要的一环。其中,Shader的优化对于游戏的性能提升起着至关重要的作用。本文将深入解析Unity中的Shader处理函数 ShaderUtil.HasProceduralInstancing ,并提供一些实用案例来展示其用法。 ShaderUtil.HasProce

    2024年02月09日
    浏览(42)
  • Unity Shader 学习笔记(4)URP渲染管线带阴影PBR-Shader模板 -- 新增可自定义阴影颜色

    材质面板截图 功能实现(URP渲染管线下): 1、进一步优化Shader结构和算法; 2、包含PBR材质; 3、投射和接收阴影,并升级 支持自定义阴影颜色 ; 4、支持点光源照射(但不支持点光源阴影)。 通用渲染截图 自定义阴影颜色截图 完整代码: 写在最后: 1、在我的上一篇文

    2024年02月12日
    浏览(50)
  • Unity Spine 3.8 (URP) 踩坑(Shader报错修改)

    今天搜索spine优化,看到一篇文章项目导入多个Spine动画 合批 降低DrawCall -- UWA问答 | 游戏开发者互动问答社区 | 侑虎科技 提供了新思路,打算尝试一下URP。但美术使用的spine版本是3.8,项目用的Unity2021.3.11f1c2,直接导入spine URP包,shader报错:half4 不能转成 SurfaceData2D;遂改下

    2024年02月12日
    浏览(49)
  • unity URP 利用particle system制作简单的shader交互

    首先这里制作了一个简单交互,使用shader grapgh,根据计算距离和变化数值的差实现交互后的扩散,同时计算消散遮罩让它逐渐谈去。 将他赋予材质物体,根据脚本传入位置和逐渐变化的大小后,呈现这样的效果。 但是,shader graph这样的工具,在做这种效果非常快的同时,也

    2024年02月07日
    浏览(44)
  • Unity URP Shader “Redefinition of _Time“ error

    强烈建议先尝试阅读本文之后自行解决:https://zhuanlan.zhihu.com/p/360566324 我这里记录一下我的思路: 首先检查URP升级是否正确,主要看Asset是否设置,ShaderGraph表现是否正常 尝试排除是否是未定义宏导致的问题,主要是对比ShaderGraph自动生成的代码 确认自己的代码是否使用了

    2024年02月15日
    浏览(36)
  • unity build-in 渲染管线升级urp渲染 shader篇

            由于工作原因需要对项目进行升级,从build-in渲染管线升级到urp渲染管线,我自己对应的unity版本是2018.版本升级到2021.3.2版本,由于最近几年unity版本升级比较快,个体版本差异有所不同,如遇与版本不一致问题敬请谅解。以下是根据官网等系列网站整理的内容

    2023年04月16日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包