在Unity LWRP中使用代码编写着色器

引言


哈Ha 今天,我想谈一谈如何快速,轻松地(几乎)开始使用轻量级渲染管道(LWRP)在Unity中编写经典文本着色器,这是可脚本化渲染管道(SRP)管道的示例之一。

但是着色器图呢?


Shader Graph是用于原型制作或编写简单效果的便捷工具。 但是,有时候,有必要写一些复杂的东西,然后-节点,自定义函数,子图的数量急剧增加,这就是为什么即使是最老练的图形程序员也开始对此感到困惑。 我们都知道,自动生成的先验代码不能比手工编写的代码好-您不需要花太多时间进行示例,因为节点布局中的任何错误都可能导致以下事实:顶点着色器中已知的计算结果将在片段中重复计算。 有些人更喜欢使用代码 ,而不是使用节点。 原因可能不同,但本质是相同的-节点向下运行,代码万岁!

2020-01-19-17-07-35

发行


那么,坐下来在LWRP下编写常规文本着色器有什么问题呢? 问题是LWRP不支持每个人喜欢的标准曲面着色器。
尝试使用它时,我们得到以下信息:

2020-01-19-17-16-16

着色器代码
Shader "Custom/NewSurfaceShader" { Properties { _Color ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _Glossiness ("Smoothness", Range(0,1)) = 0.5 _Metallic ("Metallic", Range(0,1)) = 0.0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Standard fullforwardshadows // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; half _Glossiness; half _Metallic; fixed4 _Color; // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_BUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_BUFFER_END(Props) void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; // Metallic and smoothness come from slider variables o.Metallic = _Metallic; o.Smoothness = _Glossiness; o.Alpha = ca; } ENDCG } FallBack "Diffuse" } 


然后想到尝试编写一个具有顶点和片段部分的常规anlite着色器。 幸运的是,一切正常:

2020-01-19-17-22-46

着色器代码
 Shader "Unlit/NewUnlitShader" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType"="Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert (appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); return o; } fixed4 frag (v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); return col; } ENDCG } } } 


但是,您怎么能不难过呢-我们似乎一无所有,没有光线,阴影,光照贴图和心爱的PBR ,没有它们,生活就不会那么美好。
当然,您可以手动编写所有内容:
让它发光!

2020-01-19-17-55-56

着色器代码
 Shader "TheProxor/Simple Lit" { Properties { _MainTex("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } LOD 100 Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag // make fog work #pragma multi_compile_fog #include "UnityCG.cginc" #include "UnityLightingCommon.cginc" struct appdata { float4 vertex : POSITION; float2 uv : TEXCOORD0; float3 normal : NORMAL; }; struct v2f { float2 uv : TEXCOORD0; UNITY_FOG_COORDS(1) float4 vertex : SV_POSITION; fixed4 diffuse : COLOR0; }; sampler2D _MainTex; float4 _MainTex_ST; v2f vert(appdata v) { v2f o; o.vertex = UnityObjectToClipPos(v.vertex); o.uv = TRANSFORM_TEX(v.uv, _MainTex); UNITY_TRANSFER_FOG(o,o.vertex); half3 worldNormal = UnityObjectToWorldNormal(v.normal); half nl = max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz)); o.diffuse = nl * _LightColor0; return o; } fixed4 frag(v2f i) : SV_Target { // sample the texture fixed4 col = tex2D(_MainTex, i.uv); // apply fog UNITY_APPLY_FOG(i.fogCoord, col); col *= i.diffuse; return col; } ENDCG } } } 


一切似乎正常,但这只是漫射照明。 接下来要做什么? 您可以继续手工返回所有内容,但是它又长又沉闷,并且无法以任何方式返回PBR,并且我们丢失了所有LWRP芯片。 因此,我们别无选择,只能选择LWRP,以一次魔术击退一切。

解决方案


因此,如您所知,LWRP是基于Forward-renderer构建的,这意味着它具有自己的LitForwardPass,应该在某处进行描述。 显然,在某处有一个CGInclude,其中描述了所有这些。 这是我们在以下地点进行有趣冒险的地方:
%localappdata%\ Unity \缓存\包\ packages.unity.com \ com.unity.render-pipelines.lightweight @(LWRP版本)\

实际上,到达指定地址并进入Shaders文件夹后,我们可以找到一个有趣的着色器Lit.shader 。 实际上,我们可以说搜索结束了,在这里-令人垂涎的着色器。 深入了解-我们发现以下内容:

着色器
 Shader "Lightweight Render Pipeline/Lit" { Properties { // Specular vs Metallic workflow [HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0 [MainColor] _BaseColor("Color", Color) = (0.5,0.5,0.5,1) [MainTexture] _BaseMap("Albedo", 2D) = "white" {} _Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 _GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0 _SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 _MetallicGlossMap("Metallic", 2D) = "white" {} _SpecColor("Specular", Color) = (0.2, 0.2, 0.2) _SpecGlossMap("Specular", 2D) = "white" {} [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 _BumpScale("Scale", Float) = 1.0 _BumpMap("Normal Map", 2D) = "bump" {} _OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 _OcclusionMap("Occlusion", 2D) = "white" {} _EmissionColor("Color", Color) = (0,0,0) _EmissionMap("Emission", 2D) = "white" {} // Blending state [HideInInspector] _Surface("__surface", Float) = 0.0 [HideInInspector] _Blend("__blend", Float) = 0.0 [HideInInspector] _AlphaClip("__clip", Float) = 0.0 [HideInInspector] _SrcBlend("__src", Float) = 1.0 [HideInInspector] _DstBlend("__dst", Float) = 0.0 [HideInInspector] _ZWrite("__zw", Float) = 1.0 [HideInInspector] _Cull("__cull", Float) = 2.0 _ReceiveShadows("Receive Shadows", Float) = 1.0 // Editmode props [HideInInspector] _QueueOffset("Queue offset", Float) = 0.0 // ObsoleteProperties [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} [HideInInspector] _Color("Base Color", Color) = (0.5, 0.5, 0.5, 1) [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0 [HideInInspector] _Glossiness("Smoothness", Float) = 0.0 [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0 } SubShader { // Lightweight Pipeline tag is required. If Lightweight render pipeline is not set in the graphics settings // this Subshader will fail. One can add a subshader below or fallback to Standard built-in to make this // material work with both Lightweight Render Pipeline and Builtin Unity Pipeline Tags{"RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline" "IgnoreProjector" = "True"} LOD 300 // ------------------------------------------------------------------ // Forward pass. Shades all light in a single pass. GI + emission + Fog Pass { // Lightmode matches the ShaderPassName set in LightweightRenderPipeline.cs. SRPDefaultUnlit and passes with // no LightMode tag are also rendered by Lightweight Render Pipeline Name "ForwardLit" Tags{"LightMode" = "LightweightForward"} Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard SRP library // All shaders must be compiled with HLSLcc and currently only gles is not using HLSLcc by default #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _NORMALMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _OCCLUSIONMAP #pragma shader_feature _SPECULARHIGHLIGHTS_OFF #pragma shader_feature _ENVIRONMENTREFLECTIONS_OFF #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _RECEIVE_SHADOWS_OFF // ------------------------------------- // Lightweight Pipeline keywords #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE // ------------------------------------- // Unity defined keywords #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma vertex LitPassVertex #pragma fragment LitPassFragment #include "LitInput.hlsl" #include "LitForwardPass.hlsl" ENDHLSL } Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} ZWrite On ZTest LEqual Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/ShadowCasterPass.hlsl" ENDHLSL } Pass { Name "DepthOnly" Tags{"LightMode" = "DepthOnly"} ZWrite On ColorMask 0 Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/DepthOnlyPass.hlsl" ENDHLSL } // This pass it not used during regular rendering, only for lightmap baking. Pass { Name "Meta" Tags{"LightMode" = "Meta"} Cull Off HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex LightweightVertexMeta #pragma fragment LightweightFragmentMeta #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _SPECGLOSSMAP #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitMetaPass.hlsl" ENDHLSL } Pass { Name "Lightweight2D" Tags{ "LightMode" = "Lightweight2D" } Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex vert #pragma fragment frag #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/Utils/Lightweight2D.hlsl" ENDHLSL } } FallBack "Hidden/InternalErrorShader" CustomEditor "UnityEditor.Rendering.LWRP.ShaderGUI.LitShader" } 



它仍然只是为了易于编辑而扩展,摆脱了include-s。 好吧,以您自己的方式进行一些修改。

我们得到这样的东西:

2020-01-19-18-28-13

最终的超级着色器
 Shader "TheProxor/LWRP/Dissolve + Vertex Offset" { Properties { // Specular vs Metallic workflow [HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0 [MainColor][HideInInspector] _BaseColor("Color", Color) = (0.5,0.5,0.5,1) [MainTexture][HideInInspector] _BaseMap("Albedo", 2D) = "white" {} [HideInInspector]_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 [HideInInspector]_Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 [HideInInspector]_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0 [HideInInspector]_SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 [Gamma][HideInInspector] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 [HideInInspector]_MetallicGlossMap("Metallic", 2D) = "white" {} [HideInInspector]_SpecColor("Specular", Color) = (0.2, 0.2, 0.2) [HideInInspector]_SpecGlossMap("Specular", 2D) = "white" {} [HideInInspector][ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [HideInInspector][ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 [HideInInspector]_BumpScale("Scale", Float) = 1.0 [HideInInspector]_BumpMap("Normal Map", 2D) = "bump" {} [HideInInspector]_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 [HideInInspector]_OcclusionMap("Occlusion", 2D) = "white" {} [HDR][HideInInspector]_EmissionColor("Color", Color) = (0,0,0) [HideInInspector]_EmissionMap("Emission", 2D) = "white" {} // Blending state [HideInInspector] _Surface("__surface", Float) = 0.0 [HideInInspector] _Blend("__blend", Float) = 0.0 [HideInInspector] _AlphaClip("__clip", Float) = 0.0 [HideInInspector] _SrcBlend("__src", Float) = 1.0 [HideInInspector] _DstBlend("__dst", Float) = 0.0 [HideInInspector] _ZWrite("__zw", Float) = 1.0 [HideInInspector] _Cull("__cull", Float) = 2.0 [HideInInspector]_ReceiveShadows("Receive Shadows", Float) = 1.0 // Editmode props [HideInInspector] _QueueOffset("Queue offset", Float) = 0.0 // ObsoleteProperties [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} [HideInInspector] _Color("Base Color", Color) = (0.5, 0.5, 0.5, 1) [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0 [HideInInspector] _Glossiness("Smoothness", Float) = 0.0 [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0 //    _DissolveMap("Dissolve Map", 2D) = "white" {} _DissolveFactor("Dissolve Factor", Range(0, 1)) = 0.0 _DissolveWidth("Dissolve Width", Range(0, 1)) = 0.0 [HDR]_DissolveColor("Color", Color) = (1,1,0) } SubShader { // Lightweight Pipeline tag is required. If Lightweight render pipeline is not set in the graphics settings // this Subshader will fail. One can add a subshader below or fallback to Standard built-in to make this // material work with both Lightweight Render Pipeline and Builtin Unity Pipeline Tags{"RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline" "IgnoreProjector" = "True"} LOD 300 // ------------------------------------------------------------------ // Forward pass. Shades all light in a single pass. GI + emission + Fog Pass { // Lightmode matches the ShaderPassName set in LightweightRenderPipeline.cs. SRPDefaultUnlit and passes with // no LightMode tag are also rendered by Lightweight Render Pipeline Name "ForwardLit" Tags{"LightMode" = "LightweightForward"} Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard SRP library // All shaders must be compiled with HLSLcc and currently only gles is not using HLSLcc by default #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _NORMALMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _OCCLUSIONMAP #pragma shader_feature _SPECULARHIGHLIGHTS_OFF #pragma shader_feature _ENVIRONMENTREFLECTIONS_OFF #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _RECEIVE_SHADOWS_OFF // ------------------------------------- // Lightweight Pipeline keywords #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE // ------------------------------------- // Unity defined keywords #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma vertex LitPassVertex #pragma fragment LitPassFragment #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/SurfaceInput.hlsl" #ifdef _SPECULAR_SETUP #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv) #else #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv) #endif struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 texcoord : TEXCOORD0; float2 lightmapUV : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 1); #ifdef _ADDITIONAL_LIGHTS float3 positionWS : TEXCOORD2; #endif #ifdef _NORMALMAP half4 normalWS : TEXCOORD3; // xyz: normal, w: viewDir.x half4 tangentWS : TEXCOORD4; // xyz: tangent, w: viewDir.y half4 bitangentWS : TEXCOORD5; // xyz: bitangent, w: viewDir.z #else half3 normalWS : TEXCOORD3; half3 viewDirWS : TEXCOORD4; #endif half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light #ifdef _MAIN_LIGHT_SHADOWS float4 shadowCoord : TEXCOORD7; #endif float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO float3 uvDissolve : TEXCOORD8; }; CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; half4 _BaseColor; half4 _SpecColor; half4 _EmissionColor; half _Cutoff; half _Smoothness; half _Metallic; half _BumpScale; half _OcclusionStrength; float4 _DissolveMap_ST; //    _DissolveMap float _DissolveFactor; float _DissolveWidth; float4 _DissolveColor; CBUFFER_END TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap); TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap); TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap); TEXTURE2D(_DissolveMap); SAMPLER(sampler_DissolveMap); half4 SampleMetallicSpecGloss(float2 uv, half albedoAlpha) { half4 specGloss; #ifdef _METALLICSPECGLOSSMAP specGloss = SAMPLE_METALLICSPECULAR(uv); #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A specGloss.a = albedoAlpha * _Smoothness; #else specGloss.a *= _Smoothness; #endif #else // _METALLICSPECGLOSSMAP #if _SPECULAR_SETUP specGloss.rgb = _SpecColor.rgb; #else specGloss.rgb = _Metallic.rrr; #endif #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A specGloss.a = albedoAlpha * _Smoothness; #else specGloss.a = _Smoothness; #endif #endif return specGloss; } half SampleOcclusion(float2 uv) { #ifdef _OCCLUSIONMAP // TODO: Controls things like these by exposing SHADER_QUALITY levels (low, medium, high) #if defined(SHADER_API_GLES) return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; #else half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; return LerpWhiteTo(occ, _OcclusionStrength); #endif #else return 1.0; #endif } inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData) { half4 albedoAlpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv); // half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)); outSurfaceData.alpha = Alpha(albedoAlpha.a, _BaseColor, _Cutoff); half4 specGloss = SampleMetallicSpecGloss(uv, albedoAlpha.a); outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb; #if _SPECULAR_SETUP outSurfaceData.metallic = 1.0h; outSurfaceData.specular = specGloss.rgb; #else outSurfaceData.metallic = specGloss.r; outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); #endif outSurfaceData.smoothness = specGloss.a; outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale); outSurfaceData.occlusion = SampleOcclusion(uv); outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap)); // outSurfaceData.emission = _EmissionColor.rgb * SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv); } void InitializeInputData(Varyings input, half3 normalTS, out InputData inputData) { inputData = (InputData)0; #ifdef _ADDITIONAL_LIGHTS inputData.positionWS = input.positionWS; #endif #ifdef _NORMALMAP half3 viewDirWS = half3(input.normalWS.w, input.tangentWS.w, input.bitangentWS.w); inputData.normalWS = TransformTangentToWorld(normalTS, half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz)); #else half3 viewDirWS = input.viewDirWS; inputData.normalWS = input.normalWS; #endif inputData.normalWS = NormalizeNormalPerPixel(inputData.normalWS); viewDirWS = SafeNormalize(viewDirWS); inputData.viewDirectionWS = viewDirWS; #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) inputData.shadowCoord = input.shadowCoord; #else inputData.shadowCoord = float4(0, 0, 0, 0); #endif inputData.fogCoord = input.fogFactorAndVertexLight.x; inputData.vertexLighting = input.fogFactorAndVertexLight.yzw; inputData.bakedGI = SAMPLE_GI(input.lightmapUV, input.vertexSH, inputData.normalWS); } /////////////////////////////////////////////////////////////////////////////// // Vertex and Fragment functions // /////////////////////////////////////////////////////////////////////////////// //Standard (Physically Based) shader Varyings LitPassVertex(Attributes input) { Varyings output = (Varyings)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); input.positionOS.xyz += normalize(input.positionOS.xyz) * sin(input.positionOS.x) * sin(_Time.x * 100); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); half3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS); half fogFactor = ComputeFogFactor(vertexInput.positionCS.z); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); #ifdef _NORMALMAP output.normalWS = half4(normalInput.normalWS, viewDirWS.x); output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y); output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z); #else output.normalWS = NormalizeNormalPerVertex(normalInput.normalWS); output.viewDirWS = viewDirWS; #endif OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV); OUTPUT_SH(output.normalWS.xyz, output.vertexSH); output.fogFactorAndVertexLight = half4(fogFactor, vertexLight); #ifdef _ADDITIONAL_LIGHTS output.positionWS = vertexInput.positionWS; #endif #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) output.shadowCoord = GetShadowCoord(vertexInput); #endif output.positionCS = vertexInput.positionCS; return output; } // Used in Standard (Physically Based) shader half4 LitPassFragment(Varyings input) : SV_Target { input.uv += _Time.x * 10; UNITY_SETUP_INSTANCE_ID(input); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); SurfaceData surfaceData; InitializeStandardLitSurfaceData(input.uv, surfaceData); InputData inputData; InitializeInputData(input, surfaceData.normalTS, inputData); float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; bool outline = mask.r > _DissolveFactor - _DissolveWidth; surfaceData.emission *= outline * _DissolveColor; half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha); color *= lerp(1, _DissolveColor, outline); color.rgb = MixFog(color.rgb, inputData.fogCoord); return color; } ENDHLSL } // Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} ZWrite On ZTest LEqual Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Shadows.hlsl" float3 _LightDirection; struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; float4 positionCS : SV_POSITION; }; CBUFFER_START(UnityPerMaterial) float4 _DissolveMap_ST; //    _DissolveMap float _DissolveFactor; CBUFFER_END TEXTURE2D(_DissolveMap); SAMPLER(sampler_DissolveMap); float4 GetShadowPositionHClip(Attributes input) { float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection)); #if UNITY_REVERSED_Z positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); #else positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); #endif return positionCS; } Varyings ShadowPassVertex(Attributes input) { Varyings output; input.positionOS.xyz += normalize(input.positionOS.xyz) * sin(input.positionOS.x) * sin(_Time.x * 100); UNITY_SETUP_INSTANCE_ID(input); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); output.positionCS = GetShadowPositionHClip(input); return output; } half4 ShadowPassFragment(Varyings input) : SV_TARGET { float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff); return 0; } ENDHLSL } Pass { Name "DepthOnly" Tags{"LightMode" = "DepthOnly"} ZWrite On ColorMask 0 Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #ifndef LIGHTWEIGHT_DEPTH_ONLY_PASS_INCLUDED #define LIGHTWEIGHT_DEPTH_ONLY_PASS_INCLUDED struct Attributes { float4 position : POSITION; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; Varyings DepthOnlyVertex(Attributes input) { Varyings output = (Varyings)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); input.position.xyz += normalize(input.position.xyz) * sin(input.position.x) * sin(_Time.x * 100); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); output.positionCS = TransformObjectToHClip(input.position.xyz); return output; } half4 DepthOnlyFragment(Varyings input) : SV_TARGET { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff); return 0; } #endif ENDHLSL } // Pass { Name "Meta" Tags{"LightMode" = "Meta"} Cull Off HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex LightweightVertexMeta #pragma fragment LightweightFragmentMeta #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _SPECGLOSSMAP #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/MetaInput.hlsl" #ifndef LIGHTWEIGHT_LIT_META_PASS_INCLUDED #define LIGHTWEIGHT_LIT_META_PASS_INCLUDED Varyings LightweightVertexMeta(Attributes input) { Varyings output; output.positionCS = MetaVertexPosition(input.positionOS, input.uv1, input.uv2, unity_LightmapST, unity_DynamicLightmapST); output.uv = TRANSFORM_TEX(input.uv0, _BaseMap); return output; } half4 LightweightFragmentMeta(Varyings input) : SV_Target { SurfaceData surfaceData; InitializeStandardLitSurfaceData(input.uv, surfaceData); BRDFData brdfData; InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); MetaInput metaInput; metaInput.Albedo = brdfData.diffuse + brdfData.specular * brdfData.roughness * 0.5; metaInput.SpecularColor = surfaceData.specular; metaInput.Emission = surfaceData.emission; return MetaFragment(metaInput); } #endif ENDHLSL } Pass { Name "Lightweight2D" Tags{ "LightMode" = "Lightweight2D" } Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex vert #pragma fragment frag #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/Utils/Lightweight2D.hlsl" ENDHLSL } } FallBack "Hidden/InternalErrorShader" CustomEditor "UnityEditor.Rendering.LWRP.ShaderGUI.LitShaderEditor" } 


首先,您需要确定生成的着色器中的内容。 首先,我们对以下方面感兴趣:

 CustomEditor "UnityEditor.Rendering.LWRP.ShaderGUI.LitShaderEditor" 

我们记得,其原始内容如下:

 CustomEditor "UnityEditor.Rendering.LWRP.ShaderGUI.LitShader" 

那是什么,为什么呢? 这个问题的答案非常简单-如果仔细观察,着色器具有大量不同类型的定义,奇怪的是,需要激活和停用这些定义,并且一时需要从代码中完成,这就是为什么我们需要自定义检查器的原因。 此外,我们的自定义检查器不仅应使我们有机会编辑内置属性,而且还可以编辑着色器中可能需要的属性。 原始着色器已经有一个自定义检查器,因此我们可以通过以下路径来查找它:
%localappdata%\ Unity \缓存\包\ packages.unity.com \ com.unity.render-pipelines.lightweight@6.9.2 \编辑器\ ShaderGUI \着色器\
实际上,我们对从BaseShaderGUI继承的LitShader.cs文件感兴趣:

 internal class LitShader : BaseShaderGUI { ... } 

主要批处理完全在BaseShaderGUI.cs中进行,可以在更高一级的文件夹中找到:

 public abstract class BaseShaderGUI : ShaderGUI { ... } 

我们将这些脚本放到Editor文件夹中(如果没有,请创建它们,否则在构建项目期间自然会出现错误,因为构建中不包含UnityEditor命名空间)。当然,与Internet类型SavedBool关联的是一千一百个错误,这些错误是在编辑器窗口中可序列化的bool类型的变量。这样做是为了保持材料折叠部分的状态。实际上,为了进行校正,我们执行简单的操作。

变更:

 SavedBool m_SurfaceOptionsFoldout; SavedBool m_SurfaceInputsFoldout; SavedBool m_AdvancedFoldout; 

开启:

 AnimatedValues.AnimBool m_SurfaceOptionsFoldout; AnimatedValues.AnimBool m_SurfaceInputsFoldout; AnimatedValues.AnimBool m_AdvancedFoldout; 

并为其他自定义属性添加另一个变量:

 AnimatedValues.AnimBool m_OtherFoldout; 

您还需要添加带有我们自定义参数的部分名称和说明,并遵守脚本中已建立的传统:

 protected class Styles { // Catergories ... public static readonly GUIContent OtherOptions = new GUIContent("Your own options", "You own custom options"); } 

好吧,现在让我们做点小技巧。如您所见,对于所有标准属性,我都设置了HideInInspector属性,它直接暗示该属性将在检查器中隐藏。但是,这仅与标准材料检查员相关,但是哪一个呢?是的,习惯!这意味着我们所有的内置属性都以任何方式呈现。因此,我们将它们隐藏起来:

 ... [MainColor][HideInInspector] _BaseColor("Color", Color) = (0.5,0.5,0.5,1) [MainTexture][HideInInspector] _BaseMap("Albedo", 2D) = "white" {} [HideInInspector]_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 [HideInInspector]_Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 [HideInInspector]_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0 [HideInInspector]_SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 ... 

在自定义编辑器的代码中,我们只需调用标准检查器的呈现即可:

 public override void OnGUI(...) { ... m_OtherFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_OtherFoldout.value, Styles.OtherOptions); if (m_OtherFoldout.value) { base.OnGUI(materialEditorIn, properties); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); ... } 

结果很明显:这是两个脚本的代码:

2020-01-19-22-58-23



BaseShaderEditor.cs
 using System; using UnityEngine; using UnityEngine.Rendering; using UnityEditor.Rendering; namespace UnityEditor { public abstract class BaseShaderEditor : ShaderGUI { #region EnumsAndClasses public enum SurfaceType { Opaque, Transparent } public enum BlendMode { Alpha, // Old school alpha-blending mode, fresnel does not affect amount of transparency Premultiply, // Physically plausible transparency mode, implemented as alpha pre-multiply Additive, Multiply } public enum SmoothnessSource { BaseAlpha, SpecularAlpha } public enum RenderFace { Front = 2, Back = 1, Both = 0 } protected class Styles { // Catergories public static readonly GUIContent SurfaceOptions = new GUIContent("Surface Options", "Controls how LWRP renders the Material on a screen."); public static readonly GUIContent SurfaceInputs = new GUIContent("Surface Inputs", "These settings describe the look and feel of the surface itself."); public static readonly GUIContent AdvancedLabel = new GUIContent("Advanced", "These settings affect behind-the-scenes rendering and underlying calculations."); public static readonly GUIContent surfaceType = new GUIContent("Surface Type", "Select a surface type for your texture. Choose between Opaque or Transparent."); public static readonly GUIContent blendingMode = new GUIContent("Blending Mode", "Controls how the color of the Transparent surface blends with the Material color in the background."); public static readonly GUIContent cullingText = new GUIContent("Render Face", "Specifies which faces to cull from your geometry. Front culls front faces. Back culls backfaces. None means that both sides are rendered."); public static readonly GUIContent alphaClipText = new GUIContent("Alpha Clipping", "Makes your Material act like a Cutout shader. Use this to create a transparent effect with hard edges between opaque and transparent areas."); public static readonly GUIContent alphaClipThresholdText = new GUIContent("Threshold", "Sets where the Alpha Clipping starts. The higher the value is, the brighter the effect is when clipping starts."); public static readonly GUIContent receiveShadowText = new GUIContent("Receive Shadows", "When enabled, other GameObjects can cast shadows onto this GameObject."); public static readonly GUIContent baseMap = new GUIContent("Base Map", "Specifies the base Material and/or Color of the surface. If you've selected Transparent or Alpha Clipping under Surface Options, your Material uses the Texture's alpha channel or color."); public static readonly GUIContent emissionMap = new GUIContent("Emission Map", "Sets a Texture map to use for emission. You can also select a color with the color picker. Colors are multiplied over the Texture."); public static readonly GUIContent normalMapText = new GUIContent("Normal Map", "Assigns a tangent-space normal map."); public static readonly GUIContent bumpScaleNotSupported = new GUIContent("Bump scale is not supported on mobile platforms"); public static readonly GUIContent fixNormalNow = new GUIContent("Fix now", "Converts the assigned texture to be a normal map format."); public static readonly GUIContent queueSlider = new GUIContent("Priority", "Determines the chronological rendering order for a Material. High values are rendered first."); public static readonly GUIContent OtherOptions = new GUIContent("Your own options", "You own custom options"); } #endregion #region Variables protected MaterialEditor materialEditor { get; set; } protected MaterialProperty surfaceTypeProp { get; set; } protected MaterialProperty blendModeProp { get; set; } protected MaterialProperty cullingProp { get; set; } protected MaterialProperty alphaClipProp { get; set; } protected MaterialProperty alphaCutoffProp { get; set; } protected MaterialProperty receiveShadowsProp { get; set; } // Common Surface Input properties protected MaterialProperty baseMapProp { get; set; } protected MaterialProperty baseColorProp { get; set; } protected MaterialProperty emissionMapProp { get; set; } protected MaterialProperty emissionColorProp { get; set; } protected MaterialProperty queueOffsetProp { get; set; } public bool m_FirstTimeApply = true; private const string k_KeyPrefix = "LightweightRP:Material:UI_State:"; private string m_HeaderStateKey = null; // Header foldout states AnimatedValues.AnimBool m_SurfaceOptionsFoldout; AnimatedValues.AnimBool m_SurfaceInputsFoldout; AnimatedValues.AnimBool m_AdvancedFoldout; AnimatedValues.AnimBool m_OtherFoldout; #endregion private const int queueOffsetRange = 50; //////////////////////////////////// // General Functions // //////////////////////////////////// #region GeneralFunctions public abstract void MaterialChanged(Material material); public virtual void FindProperties(MaterialProperty[] properties) { surfaceTypeProp = FindProperty("_Surface", properties); blendModeProp = FindProperty("_Blend", properties); cullingProp = FindProperty("_Cull", properties); alphaClipProp = FindProperty("_AlphaClip", properties); alphaCutoffProp = FindProperty("_Cutoff", properties); receiveShadowsProp = FindProperty("_ReceiveShadows", properties, false); baseMapProp = FindProperty("_BaseMap", properties, false); baseColorProp = FindProperty("_BaseColor", properties, false); emissionMapProp = FindProperty("_EmissionMap", properties, false); emissionColorProp = FindProperty("_EmissionColor", properties, false); queueOffsetProp = FindProperty("_QueueOffset", properties, false); } public override void OnGUI(MaterialEditor materialEditorIn, MaterialProperty[] properties) { if (materialEditorIn == null) throw new ArgumentNullException("materialEditorIn"); FindProperties(properties); // MaterialProperties can be animated so we do not cache them but fetch them every event to ensure animated values are updated correctly materialEditor = materialEditorIn; Material material = materialEditor.target as Material; // Make sure that needed setup (ie keywords/renderqueue) are set up if we're switching some existing // material to a lightweight shader. if (m_FirstTimeApply) { OnOpenGUI(material, materialEditorIn); m_FirstTimeApply = false; } ShaderPropertiesGUI(material); m_OtherFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_OtherFoldout.value, Styles.OtherOptions); if (m_OtherFoldout.value) { base.OnGUI(materialEditorIn, properties); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); foreach (var obj in materialEditor.targets) MaterialChanged((Material)obj); } public virtual void OnOpenGUI(Material material, MaterialEditor materialEditor) { // Foldout states m_HeaderStateKey = k_KeyPrefix + material.shader.name; // Create key string for editor prefs m_SurfaceOptionsFoldout = new AnimatedValues.AnimBool(true); m_SurfaceInputsFoldout = new AnimatedValues.AnimBool(true); m_AdvancedFoldout = new AnimatedValues.AnimBool(true); m_OtherFoldout = new AnimatedValues.AnimBool(true); foreach (var obj in materialEditor.targets) MaterialChanged((Material)obj); } public void ShaderPropertiesGUI(Material material) { if (material == null) throw new ArgumentNullException("material"); EditorGUI.BeginChangeCheck(); m_SurfaceOptionsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceOptionsFoldout.value, Styles.SurfaceOptions); if (m_SurfaceOptionsFoldout.value) { DrawSurfaceOptions(material); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); m_SurfaceInputsFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_SurfaceInputsFoldout.value, Styles.SurfaceInputs); if (m_SurfaceInputsFoldout.value) { DrawSurfaceInputs(material); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); m_AdvancedFoldout.value = EditorGUILayout.BeginFoldoutHeaderGroup(m_AdvancedFoldout.value, Styles.AdvancedLabel); if (m_AdvancedFoldout.value) { DrawAdvancedOptions(material); EditorGUILayout.Space(); } EditorGUILayout.EndFoldoutHeaderGroup(); DrawAdditionalFoldouts(material); if (EditorGUI.EndChangeCheck()) { foreach (var obj in materialEditor.targets) MaterialChanged((Material)obj); } } #endregion //////////////////////////////////// // Drawing Functions // //////////////////////////////////// #region DrawingFunctions public virtual void DrawSurfaceOptions(Material material) { DoPopup(Styles.surfaceType, surfaceTypeProp, Enum.GetNames(typeof(SurfaceType))); if ((SurfaceType)material.GetFloat("_Surface") == SurfaceType.Transparent) DoPopup(Styles.blendingMode, blendModeProp, Enum.GetNames(typeof(BlendMode))); EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = cullingProp.hasMixedValue; var culling = (RenderFace)cullingProp.floatValue; culling = (RenderFace)EditorGUILayout.EnumPopup(Styles.cullingText, culling); if (EditorGUI.EndChangeCheck()) { materialEditor.RegisterPropertyChangeUndo(Styles.cullingText.text); cullingProp.floatValue = (float)culling; material.doubleSidedGI = (RenderFace)cullingProp.floatValue != RenderFace.Front; } EditorGUI.showMixedValue = false; EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = alphaClipProp.hasMixedValue; var alphaClipEnabled = EditorGUILayout.Toggle(Styles.alphaClipText, alphaClipProp.floatValue == 1); if (EditorGUI.EndChangeCheck()) alphaClipProp.floatValue = alphaClipEnabled ? 1 : 0; EditorGUI.showMixedValue = false; if (alphaClipProp.floatValue == 1) materialEditor.ShaderProperty(alphaCutoffProp, Styles.alphaClipThresholdText, 1); if (receiveShadowsProp != null) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = receiveShadowsProp.hasMixedValue; var receiveShadows = EditorGUILayout.Toggle(Styles.receiveShadowText, receiveShadowsProp.floatValue == 1.0f); if (EditorGUI.EndChangeCheck()) receiveShadowsProp.floatValue = receiveShadows ? 1.0f : 0.0f; EditorGUI.showMixedValue = false; } } public virtual void DrawSurfaceInputs(Material material) { DrawBaseProperties(material); } public virtual void DrawAdvancedOptions(Material material) { materialEditor.EnableInstancingField(); if (queueOffsetProp != null) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = queueOffsetProp.hasMixedValue; var queue = EditorGUILayout.IntSlider(Styles.queueSlider, (int)queueOffsetProp.floatValue, -queueOffsetRange, queueOffsetRange); if (EditorGUI.EndChangeCheck()) queueOffsetProp.floatValue = queue; EditorGUI.showMixedValue = false; } } public virtual void DrawAdditionalFoldouts(Material material) { } public virtual void DrawBaseProperties(Material material) { if (baseMapProp != null && baseColorProp != null) // Draw the baseMap, most shader will have at least a baseMap { materialEditor.TexturePropertySingleLine(Styles.baseMap, baseMapProp, baseColorProp); // TODO Temporary fix for lightmapping, to be replaced with attribute tag. if (material.HasProperty("_MainTex")) { material.SetTexture("_MainTex", baseMapProp.textureValue); var baseMapTiling = baseMapProp.textureScaleAndOffset; material.SetTextureScale("_MainTex", new Vector2(baseMapTiling.x, baseMapTiling.y)); material.SetTextureOffset("_MainTex", new Vector2(baseMapTiling.z, baseMapTiling.w)); } } } protected virtual void DrawEmissionProperties(Material material, bool keyword) { var emissive = true; var hadEmissionTexture = emissionMapProp.textureValue != null; if (!keyword) { materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp, emissionColorProp, false); } else { // Emission for GI? emissive = materialEditor.EmissionEnabledProperty(); EditorGUI.BeginDisabledGroup(!emissive); { // Texture and HDR color controls materialEditor.TexturePropertyWithHDRColor(Styles.emissionMap, emissionMapProp, emissionColorProp, false); } EditorGUI.EndDisabledGroup(); } // If texture was assigned and color was black set color to white var brightness = emissionColorProp.colorValue.maxColorComponent; if (emissionMapProp.textureValue != null && !hadEmissionTexture && brightness <= 0f) emissionColorProp.colorValue = Color.white; // LW does not support RealtimeEmissive. We set it to bake emissive and handle the emissive is black right. if (emissive) { material.globalIlluminationFlags = MaterialGlobalIlluminationFlags.BakedEmissive; if (brightness <= 0f) material.globalIlluminationFlags |= MaterialGlobalIlluminationFlags.EmissiveIsBlack; } } public static void DrawNormalArea(MaterialEditor materialEditor, MaterialProperty bumpMap, MaterialProperty bumpMapScale = null) { if (bumpMapScale != null) { materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap, bumpMap.textureValue != null ? bumpMapScale : null); if (bumpMapScale.floatValue != 1 && UnityEditorInternal.InternalEditorUtility.IsMobilePlatform( EditorUserBuildSettings.activeBuildTarget)) if (materialEditor.HelpBoxWithButton(Styles.bumpScaleNotSupported, Styles.fixNormalNow)) bumpMapScale.floatValue = 1; } else { materialEditor.TexturePropertySingleLine(Styles.normalMapText, bumpMap); } } protected static void DrawTileOffset(MaterialEditor materialEditor, MaterialProperty textureProp) { materialEditor.TextureScaleOffsetProperty(textureProp); } #endregion //////////////////////////////////// // Material Data Functions // //////////////////////////////////// #region MaterialDataFunctions public static void SetMaterialKeywords(Material material, Action<Material> shadingModelFunc = null, Action<Material> shaderFunc = null) { // Clear all keywords for fresh start material.shaderKeywords = null; // Setup blending - consistent across all LWRP shaders SetupMaterialBlendMode(material); // Receive Shadows if (material.HasProperty("_ReceiveShadows")) CoreUtils.SetKeyword(material, "_RECEIVE_SHADOWS_OFF", material.GetFloat("_ReceiveShadows") == 0.0f); // Emission if (material.HasProperty("_EmissionColor")) MaterialEditor.FixupEmissiveFlag(material); bool shouldEmissionBeEnabled = (material.globalIlluminationFlags & MaterialGlobalIlluminationFlags.EmissiveIsBlack) == 0; if (material.HasProperty("_EmissionEnabled") && !shouldEmissionBeEnabled) shouldEmissionBeEnabled = material.GetFloat("_EmissionEnabled") >= 0.5f; CoreUtils.SetKeyword(material, "_EMISSION", shouldEmissionBeEnabled); // Normal Map if (material.HasProperty("_BumpMap")) CoreUtils.SetKeyword(material, "_NORMALMAP", material.GetTexture("_BumpMap")); // Shader specific keyword functions shadingModelFunc?.Invoke(material); shaderFunc?.Invoke(material); } public static void SetupMaterialBlendMode(Material material) { if (material == null) throw new ArgumentNullException("material"); bool alphaClip = material.GetFloat("_AlphaClip") == 1; if (alphaClip) { material.EnableKeyword("_ALPHATEST_ON"); } else { material.DisableKeyword("_ALPHATEST_ON"); } var queueOffset = 0; // queueOffsetRange; if (material.HasProperty("_QueueOffset")) queueOffset = queueOffsetRange - (int)material.GetFloat("_QueueOffset"); SurfaceType surfaceType = (SurfaceType)material.GetFloat("_Surface"); if (surfaceType == SurfaceType.Opaque) { if (alphaClip) { material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest; material.SetOverrideTag("RenderType", "TransparentCutout"); } else { material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry; material.SetOverrideTag("RenderType", "Opaque"); } material.renderQueue += queueOffset; material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.SetInt("_ZWrite", 1); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.SetShaderPassEnabled("ShadowCaster", true); } else { BlendMode blendMode = (BlendMode)material.GetFloat("_Blend"); var queue = (int)UnityEngine.Rendering.RenderQueue.Transparent; // Specific Transparent Mode Settings switch (blendMode) { case BlendMode.Alpha: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); break; case BlendMode.Premultiply: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); material.EnableKeyword("_ALPHAPREMULTIPLY_ON"); break; case BlendMode.Additive: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.One); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); break; case BlendMode.Multiply: material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.DstColor); material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.EnableKeyword("_ALPHAMODULATE_ON"); break; } // General Transparent Material Settings material.SetOverrideTag("RenderType", "Transparent"); material.SetInt("_ZWrite", 0); material.renderQueue = queue + queueOffset; material.SetShaderPassEnabled("ShadowCaster", false); } } #endregion //////////////////////////////////// // Helper Functions // //////////////////////////////////// #region HelperFunctions public static void TwoFloatSingleLine(GUIContent title, MaterialProperty prop1, GUIContent prop1Label, MaterialProperty prop2, GUIContent prop2Label, MaterialEditor materialEditor, float labelWidth = 30f) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = prop1.hasMixedValue || prop2.hasMixedValue; Rect rect = EditorGUILayout.GetControlRect(); EditorGUI.PrefixLabel(rect, title); var indent = EditorGUI.indentLevel; var preLabelWidth = EditorGUIUtility.labelWidth; EditorGUI.indentLevel = 0; EditorGUIUtility.labelWidth = labelWidth; Rect propRect1 = new Rect(rect.x + preLabelWidth, rect.y, (rect.width - preLabelWidth) * 0.5f, EditorGUIUtility.singleLineHeight); var prop1val = EditorGUI.FloatField(propRect1, prop1Label, prop1.floatValue); Rect propRect2 = new Rect(propRect1.x + propRect1.width, rect.y, propRect1.width, EditorGUIUtility.singleLineHeight); var prop2val = EditorGUI.FloatField(propRect2, prop2Label, prop2.floatValue); EditorGUI.indentLevel = indent; EditorGUIUtility.labelWidth = preLabelWidth; if (EditorGUI.EndChangeCheck()) { materialEditor.RegisterPropertyChangeUndo(title.text); prop1.floatValue = prop1val; prop2.floatValue = prop2val; } EditorGUI.showMixedValue = false; } public void DoPopup(GUIContent label, MaterialProperty property, string[] options) { DoPopup(label, property, options, materialEditor); } public static void DoPopup(GUIContent label, MaterialProperty property, string[] options, MaterialEditor materialEditor) { if (property == null) throw new ArgumentNullException("property"); EditorGUI.showMixedValue = property.hasMixedValue; var mode = property.floatValue; EditorGUI.BeginChangeCheck(); mode = EditorGUILayout.Popup(label, (int)mode, options); if (EditorGUI.EndChangeCheck()) { materialEditor.RegisterPropertyChangeUndo(label.text); property.floatValue = mode; } EditorGUI.showMixedValue = false; } // Helper to show texture and color properties public static Rect TextureColorProps(MaterialEditor materialEditor, GUIContent label, MaterialProperty textureProp, MaterialProperty colorProp, bool hdr = false) { Rect rect = EditorGUILayout.GetControlRect(); EditorGUI.showMixedValue = textureProp.hasMixedValue; materialEditor.TexturePropertyMiniThumbnail(rect, textureProp, label.text, label.tooltip); EditorGUI.showMixedValue = false; if (colorProp != null) { EditorGUI.BeginChangeCheck(); EditorGUI.showMixedValue = colorProp.hasMixedValue; int indentLevel = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; Rect rectAfterLabel = new Rect(rect.x + EditorGUIUtility.labelWidth, rect.y, EditorGUIUtility.fieldWidth, EditorGUIUtility.singleLineHeight); var col = EditorGUI.ColorField(rectAfterLabel, GUIContent.none, colorProp.colorValue, true, false, hdr); EditorGUI.indentLevel = indentLevel; if (EditorGUI.EndChangeCheck()) { materialEditor.RegisterPropertyChangeUndo(colorProp.displayName); colorProp.colorValue = col; } EditorGUI.showMixedValue = false; } return rect; } // Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties) { return FindProperty(propertyName, properties, true); } // Copied from shaderGUI as it is a protected function in an abstract class, unavailable to others public new static MaterialProperty FindProperty(string propertyName, MaterialProperty[] properties, bool propertyIsMandatory) { for (int index = 0; index < properties.Length; ++index) { if (properties[index] != null && properties[index].name == propertyName) return properties[index]; } if (propertyIsMandatory) throw new ArgumentException("Could not find MaterialProperty: '" + propertyName + "', Num properties: " + (object)properties.Length); return null; } #endregion } } 


LitShaderEditor.cs
 using System; using UnityEngine; using UnityEngine.Rendering; using UnityEditor.Rendering.LWRP; namespace UnityEditor.Rendering.LWRP.ShaderGUI { internal class LitShaderEditor : BaseShaderEditor { // Properties private LitGUI.LitProperties litProperties; // collect properties from the material properties public override void FindProperties(MaterialProperty[] properties) { base.FindProperties(properties); litProperties = new LitGUI.LitProperties(properties); } // material changed check public override void MaterialChanged(Material material) { if (material == null) throw new ArgumentNullException("material"); SetMaterialKeywords(material, LitGUI.SetMaterialKeywords); } // material main surface options public override void DrawSurfaceOptions(Material material) { if (material == null) throw new ArgumentNullException("material"); // Use default labelWidth EditorGUIUtility.labelWidth = 0f; // Detect any changes to the material EditorGUI.BeginChangeCheck(); if (litProperties.workflowMode != null) { DoPopup(LitGUI.Styles.workflowModeText, litProperties.workflowMode, Enum.GetNames(typeof(LitGUI.WorkflowMode))); } if (EditorGUI.EndChangeCheck()) { foreach (var obj in blendModeProp.targets) MaterialChanged((Material)obj); } base.DrawSurfaceOptions(material); } // material main surface inputs public override void DrawSurfaceInputs(Material material) { base.DrawSurfaceInputs(material); LitGUI.Inputs(litProperties, materialEditor, material); DrawEmissionProperties(material, true); DrawTileOffset(materialEditor, baseMapProp); } // material main advanced options public override void DrawAdvancedOptions(Material material) { if (litProperties.reflections != null && litProperties.highlights != null) { EditorGUI.BeginChangeCheck(); { materialEditor.ShaderProperty(litProperties.highlights, LitGUI.Styles.highlightsText); materialEditor.ShaderProperty(litProperties.reflections, LitGUI.Styles.reflectionsText); EditorGUI.BeginChangeCheck(); } } base.DrawAdvancedOptions(material); } public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader) { if (material == null) throw new ArgumentNullException("material"); // _Emission property is lost after assigning Standard shader to the material // thus transfer it before assigning the new shader if (material.HasProperty("_Emission")) { material.SetColor("_EmissionColor", material.GetColor("_Emission")); } base.AssignNewShaderToMaterial(material, oldShader, newShader); if (oldShader == null || !oldShader.name.Contains("Legacy Shaders/")) { SetupMaterialBlendMode(material); return; } SurfaceType surfaceType = SurfaceType.Opaque; BlendMode blendMode = BlendMode.Alpha; if (oldShader.name.Contains("/Transparent/Cutout/")) { surfaceType = SurfaceType.Opaque; material.SetFloat("_AlphaClip", 1); } else if (oldShader.name.Contains("/Transparent/")) { // NOTE: legacy shaders did not provide physically based transparency // therefore Fade mode surfaceType = SurfaceType.Transparent; blendMode = BlendMode.Alpha; } material.SetFloat("_Surface", (float)surfaceType); material.SetFloat("_Blend", (float)blendMode); if (oldShader.name.Equals("Standard (Specular setup)")) { material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Specular); Texture texture = material.GetTexture("_SpecGlossMap"); if (texture != null) material.SetTexture("_MetallicSpecGlossMap", texture); } else { material.SetFloat("_WorkflowMode", (float)LitGUI.WorkflowMode.Metallic); Texture texture = material.GetTexture("_MetallicGlossMap"); if (texture != null) material.SetTexture("_MetallicSpecGlossMap", texture); } MaterialChanged(material); } } } 


现在让我们看一下着色器的内部。

您要注意的第一件事是着色器中只有五遍。让我们对它们进行一点介绍:

  1. ForwardLit:正向传递,此处考虑光线,PBR和雾气。
  2. ShadowCaster:这是阴影的计算。
  3. 深度深度(Z缓冲区)。
  4. Meta:烤光(光照贴图)。
  5. Lightweight2D:精灵和UI。

此外,Unity具有几个不同的着色器编译器和交叉编译器。SRP需要HLSLcc。在使用OpenGL ES图形API的平台(例如Android)上,默认情况下不使用HLSLcc。

因此,我们强制它连接:

 #pragma prefer_hlslcc gles 

但是不支持DirectX 9,因此请强制将其禁用:

 #pragma exclude_renderers d3d11_9x 

在编写代码本身方面,除了现在我们不是用CG而是纯HLSL编写外,没有任何改变,因此现在着色器程序的主体将如下所示:

 HLSLPROGRAM ... ENDHLSL 

此外,我们仍然可以访问熟悉的全局变量,例如_Time_ScreenParams_WorldSpaceCameraPos。但是,UnityCG.cginc描述的许多标准功能不再对我们可用。在大多数情况下,这适用于各种矩阵转换,例如,UnityObjectToClipPos(POSITION)的类似物TransformWorldToHClip(POSITION),或者对于雾-代替UNITY_APPLY_FOG(fogCoord,color),现在我们将使用MixFog(color,fogCoord)

实际上,遵循相同的神奇路径并找到Core.hlsl文件:
%localappdata%\ Unity \缓存\包\ packages.unity.com \ com.unity.render-pipelines.lightweight @(LWRP版本)\ ShaderLibrary \ Core.hlsl

我们可以找到可用功能的完整列表。

还值得一提的是常量缓冲区(CBUFFER)和UnityPerMaterial。常量缓冲区分别用于存储在GPU上很少更改的数据,它们可以用于存储着色器变量。为此,只需调用宏
CBUFFER_STARTCBUFFER_END

 CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; half4 _BaseColor; half4 _SpecColor; half4 _EmissionColor; half _Cutoff; half _Smoothness; half _Metallic; half _BumpScale; half _OcclusionStrength; CBUFFER_END 

全局变量或各种参数设置的变量(例如,从代码或动画)的声明以旧方法在着色器程序的主体内进行。

LWRP使用两种类型的常量缓冲区-UnityPerObjectUnityPerMaterial。这些缓冲区绑定一次,以便可以在渲染期间使用它们。粗略地说,这意味着在绘制过程中,不会对常量缓冲区进行重新加固,也不会为材质调用setpass。当多个着色器共享相同的常量缓冲区时,这是有益的,因为LWRP可以为此封装不同的材质。

实际上,如果仔细研究着色器的结构,您会发现大多数标准数据到处都使用常量缓冲区。

有关所有差异的更多详细信息,但是可以使用英语阅读此处

顺便说一下,如果您仔细查看SurfaceData:
 SurfaceData surfaceData; 

你可以发现,是什么是令人垂涎的PBR法师ShaderGraph

例子



因此,现在我们的双手已经完全解开,这意味着
安排酒会的时机已到!让我们以“ 顶点位移”和“ 溶解效果为例,其余部分起舞。所有通道都摆在我们眼前非常方便,我们可以全面编辑所有内容。让我们描述这些属性:

LVRP_TextShaders_2020-01-20_21-08-42.gif





 Properties { ... _DissolveMap("Dissolve Map", 2D) = "white" {} _DissolveFactor("Dissolve Factor", Range(0, 1)) = 0.0 _DissolveWidth("Dissolve Width", Range(0, 1)) = 0.0 [HDR]_DissolveColor("Color", Color) = (1,1,0) } 

毫无疑问,这将出现在检查器中我们自己喜欢的选项卡中:添加变量:
2020-01-20_22-55-14.png



 CBUFFER_START(UnityPerMaterial) ... float4 _DissolveMap_ST; //    _DissolveMap CBUFFER_END TEXTURE2D(_DissolveMap); SAMPLER(sampler_DissolveMap); float _DissolveFactor; float _DissolveWidth; float4 _DissolveColor; 

首先,将几何体发送到醉酒的木偶:

 Varyings LitPassVertex(Attributes input) { ... input.positionOS.xyz += normalize(input.positionOS.xyz) * sin(input.positionOS.x) * sin(_Time.x * 100); ... } 

然后是阴影:
 Varyings ShadowPassVertex(Attributes input) { ... input.positionOS.xyz += normalize(input.positionOS.xyz) * sin(input.positionOS.x) * sin(_Time.x * 100); ... } 

深度:

 Varyings DepthOnlyVertex(Attributes input) { ... input.position.xyz += normalize(input.position.xyz) * sin(input.position.x) * sin(_Time.x * 100); ... } 

好吧,现在溶解时间和动作:

 half4 LitPassFragment(Varyings input) : SV_Target { ... // UV   input.uv += _Time.x * 10; //     Dissolve  float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; //  bool outline = mask.r > _DissolveFactor - _DissolveWidth; //    surfaceData.emission *= outline * _DissolveColor; //,    PBR-  half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha); //      color *= lerp(1, _DissolveColor, outline); ... } 

您还可以将Dissolve放到阴影中,然后轻按一下手腕,我们将获得正确的阴影,这在Shader Graph中很难实现,这里只有几行代码。

 half4 ShadowPassFragment(Varyings input) : SV_TARGET { ... float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; ... } 

好了,最终的着色器代码:

简单溶解
 Shader "TheProxor/LWRP/Dissolve + Vertex Offset" { Properties { // Specular vs Metallic workflow [HideInInspector] _WorkflowMode("WorkflowMode", Float) = 1.0 [MainColor][HideInInspector] _BaseColor("Color", Color) = (0.5,0.5,0.5,1) [MainTexture][HideInInspector] _BaseMap("Albedo", 2D) = "white" {} [HideInInspector]_Cutoff("Alpha Cutoff", Range(0.0, 1.0)) = 0.5 [HideInInspector]_Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 [HideInInspector]_GlossMapScale("Smoothness Scale", Range(0.0, 1.0)) = 1.0 [HideInInspector]_SmoothnessTextureChannel("Smoothness texture channel", Float) = 0 [Gamma][HideInInspector] _Metallic("Metallic", Range(0.0, 1.0)) = 0.0 [HideInInspector]_MetallicGlossMap("Metallic", 2D) = "white" {} [HideInInspector]_SpecColor("Specular", Color) = (0.2, 0.2, 0.2) [HideInInspector]_SpecGlossMap("Specular", 2D) = "white" {} [HideInInspector][ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 1.0 [HideInInspector][ToggleOff] _EnvironmentReflections("Environment Reflections", Float) = 1.0 [HideInInspector]_BumpScale("Scale", Float) = 1.0 [HideInInspector]_BumpMap("Normal Map", 2D) = "bump" {} [HideInInspector]_OcclusionStrength("Strength", Range(0.0, 1.0)) = 1.0 [HideInInspector]_OcclusionMap("Occlusion", 2D) = "white" {} [HDR][HideInInspector]_EmissionColor("Color", Color) = (0,0,0) [HideInInspector]_EmissionMap("Emission", 2D) = "white" {} // Blending state [HideInInspector] _Surface("__surface", Float) = 0.0 [HideInInspector] _Blend("__blend", Float) = 0.0 [HideInInspector] _AlphaClip("__clip", Float) = 0.0 [HideInInspector] _SrcBlend("__src", Float) = 1.0 [HideInInspector] _DstBlend("__dst", Float) = 0.0 [HideInInspector] _ZWrite("__zw", Float) = 1.0 [HideInInspector] _Cull("__cull", Float) = 2.0 [HideInInspector]_ReceiveShadows("Receive Shadows", Float) = 1.0 // Editmode props [HideInInspector] _QueueOffset("Queue offset", Float) = 0.0 // ObsoleteProperties [HideInInspector] _MainTex("BaseMap", 2D) = "white" {} [HideInInspector] _Color("Base Color", Color) = (0.5, 0.5, 0.5, 1) [HideInInspector] _GlossMapScale("Smoothness", Float) = 0.0 [HideInInspector] _Glossiness("Smoothness", Float) = 0.0 [HideInInspector] _GlossyReflections("EnvironmentReflections", Float) = 0.0 // _DissolveMap("Dissolve Map", 2D) = "white" {} _DissolveFactor("Dissolve Factor", Range(0, 1)) = 0.0 _DissolveWidth("Dissolve Width", Range(0, 1)) = 0.0 [HDR]_DissolveColor("Color", Color) = (1,1,0) } SubShader { // Lightweight Pipeline tag is required. If Lightweight render pipeline is not set in the graphics settings // this Subshader will fail. One can add a subshader below or fallback to Standard built-in to make this // material work with both Lightweight Render Pipeline and Builtin Unity Pipeline Tags{"RenderType" = "Opaque" "RenderPipeline" = "LightweightPipeline" "IgnoreProjector" = "True"} LOD 300 // ------------------------------------------------------------------ // Forward pass. Shades all light in a single pass. GI + emission + Fog Pass { // Lightmode matches the ShaderPassName set in LightweightRenderPipeline.cs. SRPDefaultUnlit and passes with // no LightMode tag are also rendered by Lightweight Render Pipeline Name "ForwardLit" Tags{"LightMode" = "LightweightForward"} Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard SRP library // All shaders must be compiled with HLSLcc and currently only gles is not using HLSLcc by default #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _NORMALMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _OCCLUSIONMAP #pragma shader_feature _SPECULARHIGHLIGHTS_OFF #pragma shader_feature _ENVIRONMENTREFLECTIONS_OFF #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _RECEIVE_SHADOWS_OFF // ------------------------------------- // Lightweight Pipeline keywords #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE // ------------------------------------- // Unity defined keywords #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma vertex LitPassVertex #pragma fragment LitPassFragment #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Lighting.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/SurfaceInput.hlsl" #ifdef _SPECULAR_SETUP #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_SpecGlossMap, sampler_SpecGlossMap, uv) #else #define SAMPLE_METALLICSPECULAR(uv) SAMPLE_TEXTURE2D(_MetallicGlossMap, sampler_MetallicGlossMap, uv) #endif struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 texcoord : TEXCOORD0; float2 lightmapUV : TEXCOORD1; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 1); #ifdef _ADDITIONAL_LIGHTS float3 positionWS : TEXCOORD2; #endif #ifdef _NORMALMAP half4 normalWS : TEXCOORD3; // xyz: normal, w: viewDir.x half4 tangentWS : TEXCOORD4; // xyz: tangent, w: viewDir.y half4 bitangentWS : TEXCOORD5; // xyz: bitangent, w: viewDir.z #else half3 normalWS : TEXCOORD3; half3 viewDirWS : TEXCOORD4; #endif half4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light #ifdef _MAIN_LIGHT_SHADOWS float4 shadowCoord : TEXCOORD7; #endif float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO float3 uvDissolve : TEXCOORD8; }; CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; half4 _BaseColor; half4 _SpecColor; half4 _EmissionColor; half _Cutoff; half _Smoothness; half _Metallic; half _BumpScale; half _OcclusionStrength; float4 _DissolveMap_ST; //    _DissolveMap CBUFFER_END TEXTURE2D(_OcclusionMap); SAMPLER(sampler_OcclusionMap); TEXTURE2D(_MetallicGlossMap); SAMPLER(sampler_MetallicGlossMap); TEXTURE2D(_SpecGlossMap); SAMPLER(sampler_SpecGlossMap); TEXTURE2D(_DissolveMap); SAMPLER(sampler_DissolveMap); float _DissolveFactor; float _DissolveWidth; float4 _DissolveColor; half4 SampleMetallicSpecGloss(float2 uv, half albedoAlpha) { half4 specGloss; #ifdef _METALLICSPECGLOSSMAP specGloss = SAMPLE_METALLICSPECULAR(uv); #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A specGloss.a = albedoAlpha * _Smoothness; #else specGloss.a *= _Smoothness; #endif #else // _METALLICSPECGLOSSMAP #if _SPECULAR_SETUP specGloss.rgb = _SpecColor.rgb; #else specGloss.rgb = _Metallic.rrr; #endif #ifdef _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A specGloss.a = albedoAlpha * _Smoothness; #else specGloss.a = _Smoothness; #endif #endif return specGloss; } half SampleOcclusion(float2 uv) { #ifdef _OCCLUSIONMAP // TODO: Controls things like these by exposing SHADER_QUALITY levels (low, medium, high) #if defined(SHADER_API_GLES) return SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; #else half occ = SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g; return LerpWhiteTo(occ, _OcclusionStrength); #endif #else return 1.0; #endif } inline void InitializeStandardLitSurfaceData(float2 uv, out SurfaceData outSurfaceData) { half4 albedoAlpha = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv); // half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)); outSurfaceData.alpha = Alpha(albedoAlpha.a, _BaseColor, _Cutoff); half4 specGloss = SampleMetallicSpecGloss(uv, albedoAlpha.a); outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb; #if _SPECULAR_SETUP outSurfaceData.metallic = 1.0h; outSurfaceData.specular = specGloss.rgb; #else outSurfaceData.metallic = specGloss.r; outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); #endif outSurfaceData.smoothness = specGloss.a; outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale); outSurfaceData.occlusion = SampleOcclusion(uv); outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap)); // outSurfaceData.emission = _EmissionColor.rgb * SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv); } void InitializeInputData(Varyings input, half3 normalTS, out InputData inputData) { inputData = (InputData)0; #ifdef _ADDITIONAL_LIGHTS inputData.positionWS = input.positionWS; #endif #ifdef _NORMALMAP half3 viewDirWS = half3(input.normalWS.w, input.tangentWS.w, input.bitangentWS.w); inputData.normalWS = TransformTangentToWorld(normalTS, half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz)); #else half3 viewDirWS = input.viewDirWS; inputData.normalWS = input.normalWS; #endif inputData.normalWS = NormalizeNormalPerPixel(inputData.normalWS); viewDirWS = SafeNormalize(viewDirWS); inputData.viewDirectionWS = viewDirWS; #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) inputData.shadowCoord = input.shadowCoord; #else inputData.shadowCoord = float4(0, 0, 0, 0); #endif inputData.fogCoord = input.fogFactorAndVertexLight.x; inputData.vertexLighting = input.fogFactorAndVertexLight.yzw; inputData.bakedGI = SAMPLE_GI(input.lightmapUV, input.vertexSH, inputData.normalWS); } /////////////////////////////////////////////////////////////////////////////// // Vertex and Fragment functions // /////////////////////////////////////////////////////////////////////////////// //Standard (Physically Based) shader Varyings LitPassVertex(Attributes input) { Varyings output = (Varyings)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_TRANSFER_INSTANCE_ID(input, output); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); input.positionOS.xyz += sin(input.positionOS.x) * sin(_Time.x * 100); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); half3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS); half fogFactor = ComputeFogFactor(vertexInput.positionCS.z); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); #ifdef _NORMALMAP output.normalWS = half4(normalInput.normalWS, viewDirWS.x); output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y); output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z); #else output.normalWS = NormalizeNormalPerVertex(normalInput.normalWS); output.viewDirWS = viewDirWS; #endif OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV); OUTPUT_SH(output.normalWS.xyz, output.vertexSH); output.fogFactorAndVertexLight = half4(fogFactor, vertexLight); #ifdef _ADDITIONAL_LIGHTS output.positionWS = vertexInput.positionWS; #endif #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) output.shadowCoord = GetShadowCoord(vertexInput); #endif output.positionCS = vertexInput.positionCS; return output; } // Used in Standard (Physically Based) shader half4 LitPassFragment(Varyings input) : SV_Target { input.uv += _Time.x * 10; UNITY_SETUP_INSTANCE_ID(input); UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); SurfaceData surfaceData; InitializeStandardLitSurfaceData(input.uv, surfaceData); InputData inputData; InitializeInputData(input, surfaceData.normalTS, inputData); float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; bool outline = mask.r > _DissolveFactor - _DissolveWidth; surfaceData.emission *= outline * _DissolveColor; half4 color = LightweightFragmentPBR(inputData, surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.occlusion, surfaceData.emission, surfaceData.alpha); color *= lerp(1, _DissolveColor, outline); color.rgb = MixFog(color.rgb, inputData.fogCoord); return color; } ENDHLSL } // Pass { Name "ShadowCaster" Tags{"LightMode" = "ShadowCaster"} ZWrite On ZTest LEqual Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma vertex ShadowPassVertex #pragma fragment ShadowPassFragment #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Shadows.hlsl" float3 _LightDirection; struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; float4 positionCS : SV_POSITION; }; CBUFFER_START(UnityPerMaterial) float4 _DissolveMap_ST; //    _DissolveMap float _DissolveFactor; CBUFFER_END TEXTURE2D(_DissolveMap); SAMPLER(sampler_DissolveMap); float4 GetShadowPositionHClip(Attributes input) { float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, _LightDirection)); #if UNITY_REVERSED_Z positionCS.z = min(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); #else positionCS.z = max(positionCS.z, positionCS.w * UNITY_NEAR_CLIP_VALUE); #endif return positionCS; } Varyings ShadowPassVertex(Attributes input) { Varyings output; input.positionOS.xyz += normalize(input.positionOS.xyz) * sin(input.positionOS.x) * sin(_Time.x * 100); UNITY_SETUP_INSTANCE_ID(input); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); output.positionCS = GetShadowPositionHClip(input); return output; } half4 ShadowPassFragment(Varyings input) : SV_TARGET { float4 mask = SAMPLE_TEXTURE2D(_DissolveMap, sampler_DissolveMap, input.uv); if (mask.r > _DissolveFactor) discard; Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff); return 0; } ENDHLSL } Pass { Name "DepthOnly" Tags{"LightMode" = "DepthOnly"} ZWrite On ColorMask 0 Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma target 2.0 #pragma vertex DepthOnlyVertex #pragma fragment DepthOnlyFragment // ------------------------------------- // Material Keywords #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A //-------------------------------------- // GPU Instancing #pragma multi_compile_instancing #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/Core.hlsl" #ifndef LIGHTWEIGHT_DEPTH_ONLY_PASS_INCLUDED #define LIGHTWEIGHT_DEPTH_ONLY_PASS_INCLUDED struct Attributes { float4 position : POSITION; float2 texcoord : TEXCOORD0; UNITY_VERTEX_INPUT_INSTANCE_ID }; struct Varyings { float2 uv : TEXCOORD0; float4 positionCS : SV_POSITION; UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO }; Varyings DepthOnlyVertex(Attributes input) { Varyings output = (Varyings)0; UNITY_SETUP_INSTANCE_ID(input); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); input.position.xyz += normalize(input.position.xyz) * sin(input.position.x) * sin(_Time.x * 100); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); output.positionCS = TransformObjectToHClip(input.position.xyz); return output; } half4 DepthOnlyFragment(Varyings input) : SV_TARGET { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input); Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff); return 0; } #endif ENDHLSL } // Pass { Name "Meta" Tags{"LightMode" = "Meta"} Cull Off HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex LightweightVertexMeta #pragma fragment LightweightFragmentMeta #pragma shader_feature _SPECULAR_SETUP #pragma shader_feature _EMISSION #pragma shader_feature _METALLICSPECGLOSSMAP #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A #pragma shader_feature _SPECGLOSSMAP #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/ShaderLibrary/MetaInput.hlsl" #ifndef LIGHTWEIGHT_LIT_META_PASS_INCLUDED #define LIGHTWEIGHT_LIT_META_PASS_INCLUDED Varyings LightweightVertexMeta(Attributes input) { Varyings output; output.positionCS = MetaVertexPosition(input.positionOS, input.uv1, input.uv2, unity_LightmapST, unity_DynamicLightmapST); output.uv = TRANSFORM_TEX(input.uv0, _BaseMap); return output; } half4 LightweightFragmentMeta(Varyings input) : SV_Target { SurfaceData surfaceData; InitializeStandardLitSurfaceData(input.uv, surfaceData); BRDFData brdfData; InitializeBRDFData(surfaceData.albedo, surfaceData.metallic, surfaceData.specular, surfaceData.smoothness, surfaceData.alpha, brdfData); MetaInput metaInput; metaInput.Albedo = brdfData.diffuse + brdfData.specular * brdfData.roughness * 0.5; metaInput.SpecularColor = surfaceData.specular; metaInput.Emission = surfaceData.emission; return MetaFragment(metaInput); } #endif ENDHLSL } Pass { Name "Lightweight2D" Tags{ "LightMode" = "Lightweight2D" } Blend[_SrcBlend][_DstBlend] ZWrite[_ZWrite] Cull[_Cull] HLSLPROGRAM // Required to compile gles 2.0 with standard srp library #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x #pragma vertex vert #pragma fragment frag #pragma shader_feature _ALPHATEST_ON #pragma shader_feature _ALPHAPREMULTIPLY_ON #include "Packages/com.unity.render-pipelines.lightweight/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.lightweight/Shaders/Utils/Lightweight2D.hlsl" ENDHLSL } } FallBack "Hidden/InternalErrorShader" CustomEditor "UnityEditor.Rendering.LWRP.ShaderGUI.LitShaderEditor" } 

结论


好了,现在该盘点一下了。显而易见,在LWRP中,甚至有可能用代码编写着色器,因为这样可以极大地使您的手松开,从而无需编写拐杖即可帮助编写酷的东西,例如您的照明系统。当然,这不能与方便和熟悉的Standard Surface Shader相提并论,但是也许有一天我会动手为LWRP和HDRP编写相同的便利模拟物,但在其他时候会更多。

有用的链接:

包含本文所有材料的存储库在材料
准备过程中发现了这一点,非官方文档
LWRP文档

Source: https://habr.com/ru/post/zh-CN485018/


All Articles