【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指令管理不同功能组合,减少不必要的变体

发展历史

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 复制代码
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

    c 复制代码
    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开始探索游戏渲染】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
龙智DevSecOps解决方案2 天前
Perforce《2025游戏技术现状报告》Part 1:游戏引擎技术的广泛影响以及生成式AI的成熟之路
人工智能·unity·游戏引擎·游戏开发·perforce
SmalBox9 天前
【URP】Unity[RendererFeatures]渲染对象RenderObjects
unity3d·游戏开发·图形学
UWA14 天前
Gears 实测室:第六期・《黑色沙漠》手游如何精准决策性能优化
性能优化·游戏开发·uwa·游戏测试
用户2946555091915 天前
在unity中,如何把敌人和玩家之间的碰撞检测的性能优化一下
游戏开发
陈尕六16 天前
从零开始的 Godot 之旅 — EP10:有限状态机(二)
godot·游戏开发
祭璃妖17 天前
关于2D人物冒险游戏闪现逻辑的实现方法
游戏开发
专注VB编程开发20年21 天前
游戏开发入门,简单小游戏原理-关于2D渲染的一些小想法
小游戏·游戏开发