博客 / 詳情

返回

【URP】Unity[內置Shader]簡單光照SimpleLit

【從UnityURP開始探索遊戲渲染】專欄-直達

SimpleLit Shader的作用與原理

SimpleLit Shader是Unity通用渲染管線(URP)中的一種輕量級着色器,主要用於低端設備或需要高效渲染的場景。它採用簡化的Blinn-Phong光照模型,不計算物理正確性和能量守恆,從而實現了比標準Lit Shader更快的渲染速度。

核心原理

  • 簡化光照模型‌:使用Blinn-Phong模型而非PBR,省略了複雜的物理計算
  • 模塊化結構‌:分為Surface Options(控制渲染方式)、Surface Inputs(描述表面特性)和Advanced Options(底層渲染設置)三部分
  • 前向渲染路徑‌:通過"UniversalForward" Pass實現,支持主光源陰影和附加光源計算
  • 變體控制‌:通過Shader Feature和Multi Compile指令管理不同功能組合,減少不必要的變體

image.png

發展歷史

SimpleLit Shader隨着URP的發展經歷了多個版本迭代:

  • 早期版本(2019-2020):作為URP首批內置Shader之一,提供基礎光照功能
  • URP 7.x時期(2021):優化了變體管理,增加了GPU實例化支持
  • URP 12.1.1(2022):完善了SubShader錯誤處理,默認返回紫色洋葱效果
  • 當前版本(2024-2025):支持DOTS Instancing,增強了與Shader Graph的兼容性

具體使用方法

基礎應用示例

  • 創建材質:在Project窗口右鍵 > Create > Material
  • 選擇Shader:在材質Inspector中,選擇"Universal Render Pipeline > Simple Lit"
  • 配置屬性:

    • Base Map:設置基礎顏色紋理
    • Base Color:調整整體色調
    • Smoothness:控制表面光滑度
    • Emission:添加自發光效果

代碼示例

csharp
// 通過代碼設置SimpleLit材質屬性
Material simpleLitMat = new Material(Shader.Find("Universal Render Pipeline/Simple Lit"));
simpleLitMat.SetTexture("_BaseMap", Resources.Load<Texture>("BaseTexture"));
simpleLitMat.SetColor("_BaseColor", Color.blue);
simpleLitMat.SetFloat("_Smoothness", 0.75f);

Shader Graph中的應用

創建SimpleLit風格Shader

  • 創建新Graph:右鍵 > Create > Shader > Universal Render Pipeline > Blank Shader Graph
  • 設置Graph設置:

    • Material設置為"Simple Lit"
    • Surface設置為"Opaque"或"Transparent"
  • 構建節點網絡:

    • 使用"Sample Texture 2D"節點獲取基礎顏色
    • 通過"Normal From Texture"節點處理法線貼圖
    • 連接"Master Stack"的對應輸入端口

示例Graph功能

  • 基礎顏色混合‌:

    • 混合紋理採樣和顏色參數
    • 添加細節遮罩控制混合強度
  • 動態高光控制‌:

    • 使用時間節點驅動高光強度變化
    • 通過頂點位置影響高光範圍
  • 邊緣發光效果‌:

    • 計算視角與法線夾角
    • 使用Fresnel節點創建邊緣光

保存與應用

  • 保存Graph後生成.shadergraph文件
  • 創建材質並選擇生成的Shader
  • 通過材質參數面板調整公開屬性

Shader simple lit 對比 Lit

SimpleLit Shader與Lit Shader的性能差異主要體現在光照模型的計算複雜度上。SimpleLit採用簡化的Blinn-Phong光照模型,而Lit基於物理渲染(PBR),兩者的性能差距和適用場景如下:

性能對比

  • 渲染效率

    SimpleLit通過忽略物理正確性和能量守恆計算,相比Lit Shader可提升約30%-50%的渲染性能,尤其在低端移動設備上表現更顯著。Lit Shader因需計算微表面模型(GGX+Smith)和複雜的光照交互,對GPU負擔較大。

  • 變體複雜度

    Lit Shader支持更多材質屬性(如金屬度、粗糙度),導致Shader變體數量遠高於SimpleLit,增加了內存和編譯開銷。SimpleLit的變體更少,適合需要快速迭代或大量實例化的場景。

材質實現能力

  • SimpleLit適用材質

    • 卡通風格表面(非PBR)
    • 低多邊形(Low Poly)美術風格
    • 需要快速渲染的靜態物體或背景元素
    • 通過調整_SpecColor_Glossiness實現簡單高光效果,但不支持動態環境光遮蔽(AO)或複雜反射。
  • Lit適用材質

    • 金屬/非金屬PBR材質(如真實感金屬、石材)
    • 需要動態光照和陰影的高質量場景
    • 支持屏幕空間全局光照(SSGI)等高級特性。

選擇建議

  • 性能優先‌:選擇SimpleLit,尤其針對移動端或低端設備。
  • 效果優先‌:需真實物理交互的場景(如角色、動態物體)使用Lit。

兩者均支持URP的GPU實例化和SRP Batcher優化,但SimpleLit在批量渲染時優勢更明顯.

卡通風格 非PBR 材質實現

核心實現原理

  • 基礎光照模型‌:採用Simple Lit的Lambert漫反射+Blinn-Phong高光組合,通過閾值化處理實現色階分離
  • 邊緣光增強‌:利用菲涅爾效應節點(Fresnel Effect Node)生成輪廓光,通過Power參數控制邊緣寬度
  • 色塊分割‌:使用Step或SmoothStep函數對光照結果進行離散化處理,形成卡通風格的色塊過渡

關鍵參數説明

  • ‌_RampThreshold:控制陰影與亮部的分界閾值,值越小陰影區域越大
  • ‌_RampSmooth:色塊邊緣的平滑過渡範圍,設為0時產生硬邊緣
  • ‌_RimPower:調整邊緣光衰減速度,值越大輪廓線越細
  • ToonSimpleLit.shader

    Shader "Universal Render Pipeline/Simple Toon"
    {
        Properties
        {
            _BaseColor("Base Color", Color) = (1,1,1,1)
            _BaseMap("Base Map", 2D) = "white" {}
            _ShadowColor("Shadow Color", Color) = (0.4,0.4,0.4,1)
            _RampThreshold("Ramp Threshold", Range(0,1)) = 0.5
            _RampSmooth("Ramp Smooth", Range(0.01,0.1)) = 0.01
            _SpecColor("Specular Color", Color) = (0.9,0.9,0.9,1)
            _SpecThreshold("Spec Threshold", Range(0,1)) = 0.5
            _SpecSmooth("Spec Smooth", Range(0,0.1)) = 0.02
            _RimPower("Rim Power", Range(0,10)) = 5
            _RimColor("Rim Color", Color) = (0.8,0.8,0.8,1)
        }
    
        SubShader
        {
            Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }
    
            HLSLINCLUDE
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
            #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    
            TEXTURE2D(_BaseMap);
            SAMPLER(sampler_BaseMap);
    
            CBUFFER_START(UnityPerMaterial)
            float4 _BaseColor;
            float4 _BaseMap_ST;
            float4 _ShadowColor;
            float _RampThreshold;
            float _RampSmooth;
            float4 _SpecColor;
            float _SpecThreshold;
            float _SpecSmooth;
            float _RimPower;
            float4 _RimColor;
            CBUFFER_END
    
            struct Attributes
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float2 uv : TEXCOORD0;
            };
    
            struct Varyings
            {
                float4 positionCS : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 normalWS : TEXCOORD1;
                float3 viewDirWS : TEXCOORD2;
                float3 positionWS : TEXCOORD3;
            };
    
            Varyings ToonPassVertex(Attributes input)
            {
                Varyings output;
                VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
                output.positionCS = vertexInput.positionCS;
                output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
    
                VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);
                output.normalWS = normalInput.normalWS;
                output.viewDirWS = GetWorldSpaceViewDir(vertexInput.positionWS);
                output.positionWS = vertexInput.positionWS;
                return output;
            }
    
            half4 ToonPassFragment(Varyings input) : SV_Target
            {
                // 基礎紋理採樣
                half4 baseMap = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv);
                half3 baseColor = baseMap.rgb * _BaseColor.rgb;
    
                // 光照計算
                Light mainLight = GetMainLight();
                float3 lightDir = normalize(mainLight.direction);
                float3 normalWS = normalize(input.normalWS);
                float NdotL = dot(normalWS, lightDir);
    
                // 漫反射色階化
                float diffuse = smoothstep(_RampThreshold - _RampSmooth, 
                                          _RampThreshold + _RampSmooth, 
                                          NdotL * 0.5 + 0.5);
                float3 diffuseColor = lerp(_ShadowColor.rgb, 1, diffuse) * baseColor;
    
                // 高光計算
                float3 viewDir = normalize(input.viewDirWS);
                float3 halfDir = normalize(lightDir + viewDir);
                float specular = pow(max(0, dot(normalWS, halfDir)), 32);
                specular = smoothstep(_SpecThreshold - _SpecSmooth,
                                     _SpecThreshold + _SpecSmooth,
                                     specular);
                float3 specularColor = specular * _SpecColor.rgb * mainLight.color;
    
                // 邊緣光
                float rim = 1 - max(0, dot(viewDir, normalWS));
                rim = pow(rim, _RimPower);
                float3 rimColor = rim * _RimColor.rgb;
    
                // 最終合成
                float3 finalColor = diffuseColor * mainLight.color + specularColor + rimColor;
                return half4(finalColor, baseMap.a);
            }
            ENDHLSL
    
            Pass
            {
                Name "ToonPass"
                Tags { "LightMode"="UniversalForward" }
    
                HLSLPROGRAM
                #pragma vertex ToonPassVertex
                #pragma fragment ToonPassFragment
                ENDHLSL
            }
        }
    }

擴展優化建議

  • 添加色階貼圖‌:使用1D紋理控制光照過渡曲線,實現更復雜的卡通色階效果
  • 描邊效果‌:通過背面擠出法或後處理實現輪廓描邊(需額外Pass)
  • 材質變體‌:通過Shader變體支持不同風格切換(如賽璐璐/水彩風格)

該Shader保留了URP輕量級特性,通過HLSL重寫光照模型實現非PBR卡通效果,可直接在URP項目中使用。如需更復雜的藝術控制,可參考原神風格的貼圖通道分配方案

性能優化建議

  • 變體控制‌:禁用不必要的Shader變體(如_SPECGLOSSMAP)減少內存佔用
  • GPU Instancing‌:對相同材質的對象啓用實例化減少Draw Call
  • 紋理壓縮‌:使用適當的壓縮格式減少顯存佔用
  • LOD組合‌:與複雜Shader配合使用,根據距離切換SimpleLit

SimpleLit Shader通過簡化光照計算在保持基本視覺效果的同時顯著提升渲染效率,特別適合移動平台和低端設備,是URP管線中平衡性能與效果的重要工具


【從UnityURP開始探索遊戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,🙏)
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.