Unity SRP 管线【第四讲:URP 阴影】

URP 全文源码解析参照

引入

在UniversalRenderer.cs/ line 505行处
此处已经准备好了所有渲染数据(所有数据全部存储在了renderingData中)
我们只用renderingData中的数据初设置mainLightShadows

bool mainLightShadows = m_MainLightShadowCasterPass.Setup(ref renderingData);
bool additionalLightShadows = m_AdditionalLightsShadowCasterPass.Setup(ref renderingData);
bool transparentsNeedSettingsPass = m_TransparentSettingsPass.Setup(ref renderingData);

进入函数 m_MainLightShadowCasterPass.Setup(ref renderingData);

在这里插入图片描述

文章目录

  • URP 全文源码解析参照
  • 引入
  • MainLightShadowCasterPass.cs
    • 一、MainLightShadowCasterPass 创建
      • 参数:
        • 基类参数
        • 自定义参数
        • GPU ID参数
    • 二、MainLightShadowCasterPass 初始化
      • 1. 初始化数据(矩阵、cascade分割、切片)
      • 2. 一些条件判断,未通过的话将ShadowMap置为默认值
      • 3. 设置数据
            • (1)m_ShadowCasterCascadesCount
            • (2)RenderTexture 大小
            • (3)提取级联阴影的光照矩阵以及包围球
            • (4)获取新的临时阴影纹理
            • (5)存储renderingData中的阴影数据
      • 4. 绑定渲染目标和清除状态
      • 5. 执行 Execute
    • 三、Execute 阴影参数设置
  • GPU中的阴影数据

MainLightShadowCasterPass.cs

一、MainLightShadowCasterPass 创建

public MainLightShadowCasterPass(RenderPassEvent evt)

在UniversalRenderer管线创建的时候,我们已经做了创建

我们设置MainLightShadow在RenderingShadows(Event = 50)之前

// UniversalRenderer.cs
public UniversalRenderer(UniversalRendererData data) : base(data)
{...m_MainLightShadowCasterPass = new MainLightShadowCasterPass(RenderPassEvent.BeforeRenderingShadows);m_AdditionalLightsShadowCasterPass = new AdditionalLightsShadowCasterPass(RenderPassEvent.BeforeRenderingShadows);...
}

创建MainLightShadowCasterPass

参数:

基类参数
public RenderPassEvent renderPassEvent { get; set; }
int renderTargetWidth { get; set; }
int renderTargetHeight { get; set; }
自定义参数
const int k_MaxCascades = 4;
const int k_ShadowmapBufferBits = 16;
float m_CascadeBorder;                  // 边缘模糊度(0~1)
float m_MaxShadowDistanceSq;			// 最大阴影距离的平方
int m_ShadowCasterCascadesCount;		// 当前设置的Cascades数量RenderTargetHandle m_MainLightShadowmap;           //临时阴影纹理Shader中的索引ID
internal RenderTexture m_MainLightShadowmapTexture;//实际临时阴影纹理,以及设置(深度为16位)Matrix4x4[] m_MainLightShadowMatrices;// 阴影矩阵
ShadowSliceData[] m_CascadeSlices;    // 级联阴影切片数据,包含(//splitData、       级联阴影数据(由UNITY内置函数提供)//offsetX/Y、       级联阴影偏移//resolution        级联阴影分辨率//shadowTransform   级联阴影矩阵
Vector4[] m_CascadeSplitDistances;    // 包围球数据(xyz:位置,w:半径)
GPU ID参数
private static class MainLightShadowConstantBuffer
{public static int _WorldToShadow;public static int _ShadowParams;public static int _CascadeShadowSplitSpheres0;public static int _CascadeShadowSplitSpheres1;public static int _CascadeShadowSplitSpheres2;public static int _CascadeShadowSplitSpheres3;public static int _CascadeShadowSplitSphereRadii;public static int _ShadowOffset0;public static int _ShadowOffset1;public static int _ShadowOffset2;public static int _ShadowOffset3;public static int _ShadowmapSize;
}
MainLightShadowConstantBuffer._WorldToShadow = Shader.PropertyToID("_MainLightWorldToShadow");
MainLightShadowConstantBuffer._ShadowParams = Shader.PropertyToID("_MainLightShadowParams");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres0 = Shader.PropertyToID("_CascadeShadowSplitSpheres0");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres1 = Shader.PropertyToID("_CascadeShadowSplitSpheres1");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres2 = Shader.PropertyToID("_CascadeShadowSplitSpheres2");
MainLightShadowConstantBuffer._CascadeShadowSplitSpheres3 = Shader.PropertyToID("_CascadeShadowSplitSpheres3");
MainLightShadowConstantBuffer._CascadeShadowSplitSphereRadii = Shader.PropertyToID("_CascadeShadowSplitSphereRadii");
MainLightShadowConstantBuffer._ShadowOffset0 = Shader.PropertyToID("_MainLightShadowOffset0");
MainLightShadowConstantBuffer._ShadowOffset1 = Shader.PropertyToID("_MainLightShadowOffset1");
MainLightShadowConstantBuffer._ShadowOffset2 = Shader.PropertyToID("_MainLightShadowOffset2");
MainLightShadowConstantBuffer._ShadowOffset3 = Shader.PropertyToID("_MainLightShadowOffset3");
MainLightShadowConstantBuffer._ShadowmapSize = Shader.PropertyToID("_MainLightShadowmapSize");
m_MainLightShadowmap.Init("_MainLightShadowmapTexture");

二、MainLightShadowCasterPass 初始化

public bool Setup(ref RenderingData renderingData){}

1. 初始化数据(矩阵、cascade分割、切片)

Clear();

2. 一些条件判断,未通过的话将ShadowMap置为默认值

… 这里不作为重点

3. 设置数据

SetUp函数主要是将数据整理保存到类内参数中供类使用
其中设置的数据有:

(1)m_ShadowCasterCascadesCount

光源级联阴影数量

(2)RenderTexture 大小
renderTargetWidth;
renderTargetHeight;
(3)提取级联阴影的光照矩阵以及包围球
  1. Vector4[] m_CascadeSplitDistances[cascadeIndex] 包围球数据(xyz:位置,w:半径)
  2. ShadowSliceData[] m_CascadeSlices; 级联阴影切片数据
public struct ShadowSliceData
{public Matrix4x4 viewMatrix;public Matrix4x4 projectionMatrix;public Matrix4x4 shadowTransform;//projectionMatrix * viewMatrixpublic int offsetX;			     //ShadowAtlasMap行偏移public int offsetY;				 //ShadowAtlasMap列偏移public int resolution;			 //分辨率public ShadowSplitData splitData;//splitData包含筛选信息
}

提取函数

for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{bool success = ShadowUtils.ExtractDirectionalLightMatrix(ref renderingData.cullResults, ref renderingData.shadowData,shadowLightIndex, cascadeIndex, renderTargetWidth, renderTargetHeight, shadowResolution, light.shadowNearPlane,out m_CascadeSplitDistances[cascadeIndex], out m_CascadeSlices[cascadeIndex]);if (!success)return SetupForEmptyRendering(ref renderingData);
}
(4)获取新的临时阴影纹理
m_MainLightShadowmapTexture = ShadowUtils.GetTemporaryShadowTexture(renderTargetWidth, renderTargetHeight, k_ShadowmapBufferBits);
(5)存储renderingData中的阴影数据
m_MaxShadowDistanceSq = renderingData.cameraData.maxShadowDistance * renderingData.cameraData.maxShadowDistance;
m_CascadeBorder = renderingData.shadowData.mainLightShadowCascadeBorder;

4. 绑定渲染目标和清除状态

public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{ConfigureTarget(new RenderTargetIdentifier(m_MainLightShadowmapTexture), m_MainLightShadowmapTexture.depthStencilFormat, renderTargetWidth, renderTargetHeight, 1, true);ConfigureClear(ClearFlag.All, Color.black);
}

5. 执行 Execute

public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{if (m_CreateEmptyShadowmap){SetEmptyMainLightCascadeShadowmap(ref context);return;}RenderMainLightCascadeShadowmap(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);
}

三、Execute 阴影参数设置

RenderMainLightCascadeShadowmap(ref context, ref renderingData.cullResults, ref renderingData.lightData, ref renderingData.shadowData);

参数设置多引用ShadowsUtils单例中的函数设置
进入函数RenderMainLightCascadeShadowmap

// settings 中为阴影所需要的数据
var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex);
settings.useRenderingLayerMaskTest = UniversalRenderPipeline.asset.supportsLightLayers;for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{settings.splitData = m_CascadeSlices[cascadeIndex].splitData;// 偏移量Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution);ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false);ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex],ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix);
}shadowData.isKeywordSoftShadowsEnabled = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows;
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, shadowData.mainLightShadowCascadesCount == 1);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, shadowData.isKeywordSoftShadowsEnabled);SetupMainLightShadowReceiverConstants(cmd, shadowLight, shadowData.supportsSoftShadows);
  1. SetupShadowCasterConstantBuffer
// 阴影偏移
cmd.SetGlobalVector("_ShadowBias", shadowBias);// 世界空间光照方向,用于支持阴影法线偏移(normal bias).
Vector3 lightDirection = -shadowLight.localToWorldMatrix.GetColumn(2);
cmd.SetGlobalVector("_LightDirection", new Vector4(lightDirection.x, lightDirection.y, lightDirection.z, 0.0f));// 世界空间光源位置
Vector3 lightPosition = shadowLight.localToWorldMatrix.GetColumn(3);
cmd.SetGlobalVector("_LightPosition", new Vector4(lightPosition.x, lightPosition.y, lightPosition.z, 1.0f));
  1. 关闭精确光源阴影 PunctualLightShadow(点光源、方向光、聚光灯)
/*  "_CASTING_PUNCTUAL_LIGHT_SHADOW"  */
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false);
  1. 渲染cascade阴影
    设置默认全局偏移(这应该就是为什么,在unity中,将light的bias都设为0,但还是没有明显的摩尔纹)
cmd.SetGlobalDepthBias(1.0f, 2.5f); // these values match HDRP defaults 

设置Viewport、矩阵信息

cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution));
cmd.SetViewProjectionMatrices(view, proj);

渲染阴影,禁用硬件剪刀矩阵(不知道是什么)

context.DrawShadows(ref settings);
cmd.DisableScissorRect();
  1. 是否开启主光源阴影、主光源级联阴影、主光源软阴影
/*"_MAIN_LIGHT_SHADOWS"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, shadowData.mainLightShadowCascadesCount == 1);
/*"_MAIN_LIGHT_SHADOWS_CASCADE"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1);
/*"_SHADOWS_SOFT"*/
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, shadowData.isKeywordSoftShadowsEnabled);
  1. 设置阴影接收常量

    1. 阴影贴图 “_MainLightShadowmapTexture
    2. 光源矩阵 “_MainLightWorldToShadow”(级联矩阵为多个矩阵 Matrix4x4[])
    3. 阴影参数 “_MainLightShadowParams
      • x :阴影强度
      • y :是否软阴影(1为软,0为硬)
      • z :阴影衰减部分的衰减斜率
      • w:横坐标0处阴影开始衰减部分的纵坐标
    4. 级联阴影数据:
      四个级联的包围球数据(4 * Vector4) _CascadeShadowSplitSpheres0、1、2、3
      四个级联的半径的平方(1 * Vector4) _CascadeShadowSplitSphereRadii
    5. 软阴影:
      阴影像素偏移(左下、右下、左上、右上) _MainLightShadowOffset0/1/2/3
      阴影偏移量(偏移x,偏移y,shadowMap宽,shadowMap长 _MainLightShadowmapSize
  2. 在渲染结束后释放临时Texture

public override void OnCameraCleanup(CommandBuffer cmd)
{if (cmd == null)throw new ArgumentNullException("cmd");if (m_MainLightShadowmapTexture){RenderTexture.ReleaseTemporary(m_MainLightShadowmapTexture);m_MainLightShadowmapTexture = null;}
}

GPU中的阴影数据

Shadows.hlsl

SCREENSPACE_TEXTURE(_ScreenSpaceShadowmapTexture);
SAMPLER(sampler_ScreenSpaceShadowmapTexture);TEXTURE2D_SHADOW(_MainLightShadowmapTexture);
SAMPLER_CMP(sampler_MainLightShadowmapTexture);TEXTURE2D_SHADOW(_AdditionalLightsShadowmapTexture);
SAMPLER_CMP(sampler_AdditionalLightsShadowmapTexture);CBUFFER_START(MainLightShadows)// Last cascade is initialized with a no-op matrix. It always transforms// shadow coord to half3(0, 0, NEAR_PLANE). We use this trick to avoid// branching since ComputeCascadeIndex can return cascade index = MAX_SHADOW_CASCADESfloat4x4    _MainLightWorldToShadow[MAX_SHADOW_CASCADES + 1];float4      _CascadeShadowSplitSpheres0;float4      _CascadeShadowSplitSpheres1;float4      _CascadeShadowSplitSpheres2;float4      _CascadeShadowSplitSpheres3;float4      _CascadeShadowSplitSphereRadii;half4       _MainLightShadowOffset0;half4       _MainLightShadowOffset1;half4       _MainLightShadowOffset2;half4       _MainLightShadowOffset3;half4       _MainLightShadowParams;   // (x: shadowStrength, y: 1.0 if soft shadows, 0.0 otherwise, z: main light fade scale, w: main light fade bias)float4      _MainLightShadowmapSize;  // (xy: 1/width and 1/height, zw: width and height)
CBUFFER_END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/220664.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SVM —— 理论推导

SVM 支持向量线性可分最大间隔超平面最大间隔超平面的推导支持向量分类间隔的推导最优化问题 对偶问题拉格朗日乘子法强对偶性 SVM 优化软间隔解决问题优化目标及求解 核函数线性不可分核函数的作用常见核函数 SVM 算法优缺点 支持向量机&#xff08;Support Vector Machine&am…

AR室内导航如何实现?技术与原理分析

随着科技的进步&#xff0c;我们生活中许多方面正在被重新定义。其中之一就是导航&#xff0c;尤其是室内导航。增强现实&#xff08;AR&#xff09;技术的出现为室内导航带来了革命性的变革。本文将深入探讨AR室内导航的技术与原理&#xff0c;以及它如何改变我们的生活方式。…

【组合数学】生成函数

目录 1.形式幂级数2.生成函数性质3.生成函数求解递推关系4.生成函数在计数问题中的应用 1.形式幂级数 生成函数是解决计数问题的一种有效方法&#xff0c;它的中心思想是&#xff1a;对于一个有限或无限数列 a 0 , a 1 , a 2 , . . . {a_0,a_1,a_2,...} a0​,a1​,a2​,...&am…

数据分析的基本步骤

了解过数据分析的概念之后&#xff0c;我们再来说下数据分析的常规步骤。 明确目标 首先我们要确定一个目标&#xff0c;即我们要从数据中得到什么。比如我们要看某个指标A随时间的变化趋势&#xff0c;以期进行简单的预测。 数据收集 当确定了目标之后&#xff0c;就有了取…

SQL Server 查询处理过程

查询处理--由 SQL Server 中的关系引擎执行&#xff0c;它获取编写的 T-SQL 语句并将其转换为可以向存储引擎发出请求并检索所需结果的过程。 SQL Server 需要四个步骤来处理查询&#xff1a;分析、代化、优化和执行。 前三个步骤都由关系引擎执行&#xff1b;第三步输出的是…

camera曝光时间

曝光和传感器读数 相机上的图像采集过程由两个不同的部分组成。第一部分是曝光。曝光完成后&#xff0c;第二步就是从传感器的寄存器中读取数据并传输&#xff08;readout&#xff09;。 曝光&#xff1a;曝光是图像传感器进行感光的一个过程&#xff0c;相机曝光时间&#xf…

深度学习中的潜在空间

1 潜在空间定义 Latent Space 潜在空间&#xff1a;Latent &#xff0c;这个词的语义是“隐藏”的意思。“Latent Space 潜在空间”也可以理解为“隐藏的空间”。Latent Space 这一概念是十分重要的&#xff0c;它在“深度学习”领域中处于核心地位&#xff0c;即它是用来学习…

和葡萄酒时为什么要写品酒笔记?

如果你不把你的想法写下来&#xff0c;它们可能会在你离开房间之前就离开你的大脑。写笔记&#xff0c;包括令人难忘的品酒笔记&#xff0c;它是关于记录一些超越今天和明天的有意义的事情。这是你的记忆葡萄酒&#xff0c;对你来说最相关、最有区别的就是最重要的。最后&#…

桌面概率长按键盘无法连续输入问题

问题描述&#xff1a;概率性长按键盘无法连续输入文本 问题定位&#xff1a; 系统按键流程分析 图一 系统按键流程 按键是由X Server接收的&#xff0c;这一点只要明白了X Window的工作机制就不难理解了。X Server在接收到按键后&#xff0c;会转发到相应程序的窗口中。在窗…

CogVLM与CogAgent:开源视觉语言模型的新里程碑

引言 随着机器学习的快速发展&#xff0c;视觉语言模型&#xff08;VLM&#xff09;的研究取得了显著的进步。今天&#xff0c;我们很高兴介绍两款强大的开源视觉语言模型&#xff1a;CogVLM和CogAgent。这两款模型在图像理解和多轮对话等领域表现出色&#xff0c;为人工智能的…

【算法日志】非排序数组的二分查找应用

文章目录 前言 二分查找是一种比较简单且基础的查找算法&#xff0c;多用于排序数组的快速查找。但其实二分查找也有非排序数组的应用。 引例 Leetcode162 寻找峰值 本题是一道经典的二分查找算法题&#xff0c;要求找到一个比左右相邻值大的峰值。如果用暴力解法&#xff0…

【网络安全】网络防护之旅 - Java安全机制探秘与数字证书引爆网络防线

&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《网络安全之道 | 数字征程》⏰墨香寄清辞&#xff1a;千里传信如电光&#xff0c;密码奥妙似仙方。 挑战黑暗剑拔弩张&#xff0c;网络战场誓守长。 目录 &#x1f608;1. 初识网络安…

JS的浅拷贝和深拷贝

首先理解什么是浅拷贝和深拷贝&#xff1a; 浅拷贝&#xff1a; 浅拷贝只会复制对象的第一层属性&#xff0c;而不会递归地复制嵌套的对象。浅拷贝仅复制对象的引用&#xff0c;新对象和原始对象仍然共享相同的引用&#xff0c;因此对新对象的修改可能会影响到原始对象。浅拷…

自动化测试 (五) 读写64位操作系统的注册表

自动化测试经常需要修改注册表 很多系统的设置&#xff08;比如&#xff1a;IE的设置&#xff09;都是存在注册表中。 桌面应用程序的设置也是存在注册表中。 所以做自动化测试的时候&#xff0c;经常需要去修改注册表 Windows注册表简介 注册表编辑器在 C:\Windows\regedit…

WebSocket开发

目录 前言 1.介绍 2.原理解析 3.简单的聊天室搭建 4.点到点消息传输 总结 前言 WebSocket 是互联网项目中画龙点睛的应用&#xff0c;可以用于消息推送、站内信、在线聊天等业务。 1.介绍 WebSocket 是一种基于 TCP 的新网络协议&#xff0c;它是一种持久化的协议&…

Java精品项目源码新基于协同过滤算法的旅游推荐系统(编号V69)

Java精品项目源码新基于协同过滤算法的旅游推荐系统(编号V69) 大家好&#xff0c;小辰今天给大家介绍一个基于协同过滤算法的旅游推荐系统

056:vue工具 --- CSS在线格式化

第056个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

Netty应用(七) ----MQTT编解码器

目录 0.前言1. MqttEncoder--编码器1.1 构造方法1.2 encodeConnectMessage -- 连接消息1.3 encodeConnAckMessage - 确认连接1.4 encodePublishMessage -- 发布消息1.5 encodeSubscribeMessage - 订阅主题1.6 encodeUnsubscribeMessage - 取消订阅1.7 encodeSubAckMessage - 订…

HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】

一.HarmonyOS应用开发实战—开箱即用的应用首页页面【ArkTS】【鸿蒙专栏-34】 1.1 项目背景 HarmonyOS(鸿蒙操作系统)是华为公司推出的一种分布式操作系统。它被设计为一种全场景、全连接的操作系统,旨在实现在各种设备之间的无缝协同和共享,包括智能手机、平板电脑、智能…

计算机网络(四)

九、网络安全 &#xff08;一&#xff09;什么是网络安全&#xff1f; A、网络安全状况 分布式反射攻击逐渐成为拒绝攻击的重要形式 涉及重要行业和政府部门的高危漏洞事件增多。 基础应用和通用软硬件漏洞风险凸显&#xff08;“心脏出血”&#xff0c;“破壳”等&#x…