【URP】[平面阴影]原理与实现

【从UnityURP开始探索游戏渲染】专栏-直达

实现原理

光源点L0,光源方向L,光源距离要投影的的平面距离d;要投影的平面的向上法线向量TerrainNormal,平面上的任意点TerrainPos;现在要计算出光源投向空间中模型上的点在平面上的平面投影点坐标P。

  • 示意图:

计算公式

  • 平面上任意向量与该平面法向量点乘为0: (p-TerrainPos)·TerrainNormal=0
  • 平面映射的P点是由光射到顶点延伸得到的: p=d\*L+L0
  • 由上述两个公式联立方程,带入求解d:
  • d=((TerrainPos-L0)·TerrainNormal)/(L·TerrainNormal)

示例

实现要点说明:

  • 使用URP核心库(ShaderLibrary/Core.hlsl)确保兼容性
  • 通过_CBUFFER_START声明材质属性
  • 顶点着色器中实现完整投影公式计算
  • 添加透明度衰减效果增强真实感
  • 使用Transparent渲染队列和混合模式
  • 禁用ZWrite避免深度冲突

使用方式:

  • 创建材质并指定该Shader

  • 通过C#脚本设置_LightPos等参数

  • 将材质应用到需要投射阴影的物体上

  • 确保接收阴影的平面有适当渲染材质

  • PlaneShadow.shader

    cpp 复制代码
    Shader "Custom/PlaneShadow"
    {
        Properties
        {
            _ShadowColor("Shadow Color", Color) = (0,0,0,0.5)
        }
    
        SubShader
        {
            Tags { "RenderType"="Transparent" "Queue"="Transparent" }
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
    
            Pass
            {
                HLSLPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    
                struct Attributes
                {
                    float4 positionOS : POSITION;
                };
    
                struct Varyings
                {
                    float4 positionCS : SV_POSITION;
                    float alpha : TEXCOORD0;
                };
    
                CBUFFER_START(UnityPerMaterial)
                float4 _ShadowColor;
                CBUFFER_END
    
                // 外部传入参数
                float3 _LightPos;    // 光源位置L0
                float3 _LightDir;    // 光源方向L(需归一化)
                float3 _TerrainPos;  // 平面上任意点
                float3 _TerrainNormal; // 平面法线(需归一化)
    
                Varyings vert(Attributes IN)
                {
                    Varyings OUT;
    
                    // 计算投影参数d
                    float d = dot((_TerrainPos - _LightPos), _TerrainNormal) / 
                              dot(_LightDir, _TerrainNormal);
    
                    // 计算模型顶点到光源的向量
                    float3 lightToVertex = IN.positionOS.xyz - _LightPos;
    
                    // 计算投影点P = L0 + (d / (L·(V-L0))) * (V-L0)
                    float t = d / dot(_LightDir, lightToVertex);
                    float3 shadowPos = _LightPos + t * lightToVertex;
    
                    // 转换到裁剪空间
                    OUT.positionCS = TransformWorldToHClip(shadowPos);
                    
                    // 根据距离计算透明度衰减
                    OUT.alpha = saturate(1.0 - length(shadowPos - IN.positionOS.xyz) * 0.1);
                    return OUT;
                }
    
                half4 frag(Varyings IN) : SV_Target
                {
                    half4 col = _ShadowColor;
                    col.a *= IN.alpha;
                    return col;
                }
                ENDHLSL
            }
        }
    }

【从UnityURP开始探索游戏渲染】专栏-直达

(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
Jmyd012314 分钟前
博物馆数字展厅系统架构设计:实景采集到云渲染全链路
unity·系统架构·博物馆·数字展厅·博物馆数字化
weixin_424294674 小时前
对于未加入 Script Execution Order 的脚本
unity
暴走约伯4 小时前
【VFX工具链源码拆解 03】告别机械劳动(下):材质字典映射批处理与智能纹理槽识别
unity·游戏引擎·材质
Wanda12144 小时前
机器人与机电一体化3D数字孪生机器-Day9
人工智能·3d·unity·机器人·数字孪生
暴走约伯5 小时前
【VFX工具链源码拆解 01】总体架构:大型项目特效流程的程序化落地
开发语言·经验分享·3d·unity·架构·游戏引擎
平行云1 天前
建筑BIM/3D可视化轻量级实时评审与分享方案
unity·ue5·3dsmax·实时云渲染·云桌面·云游戏·建筑bim
2501_915106322 天前
Windows 上开发 Unity iOS,使用 KXBuild 进行真机调试、性能采样与打包 ipa
windows·vscode·unity·ios·个人开发·swift·敏捷流程
FFFFujige2 天前
【Unity】一个的Dots用Ruhanka踩坑记录
unity·游戏引擎
凯基迪科技3 天前
Unity游戏加密锁逆向方案、选型与攻防分析
游戏·unity·游戏引擎
阿松爱学习3 天前
【Unity开发】局部区域截图功能实现
unity·c#