【渲染流水线】[应用阶段]-[渲染命令队列]以UnityURP为例
应用阶段最后是CPU向GPU提交需要渲染的数据。通常数据会被复制到显存中,然后设置渲染参数,最后调用渲染接口。PC中是这样的,但是移动设备一般没有单独的显存。使用内存为GPU服务。他们使用同一内存地址。除非要读/写这段内存内容才会复制出一份调整CPU和GPU之间协作。
【从UnityURP开始探索游戏渲染】专栏-直达
渲染状态:
- 一连串开关或方法,以及方法的地址指向(阶段中的各种可配置的阶段等都是在这里)。SetPassCall。例如是否开启混合、用哪个纹理、哪个顶点着色器、是否背面剔除等,在Unity中则是ShaderLab语法规则中规定的各种标签。
渲染指令:
- 调用具体渲染的对象。drawcall是一个渲染指令,这个指令仅指向一连串图元(点线面 网格拆分后的状态),并不会包含任何其他材质信息。每个状态前都伴随着一连串渲染状态设置,所以渲染命令队列中,渲染状态和渲染指令是交替出现。
渲染命令队列:
- 其中包含渲染状态、渲染指令的缓冲区。CPU向缓冲区放入指令,GPU执行指令。CPU发送渲染状态后,CPU需要控制总线将数据从内存搬运到显存,搬运过程耗费大量时间。drawcall多了后会导致大量内存搬运,运行速度下降。
打包数据
模型信息
模型数据主要从网格资源(Mesh)中获取,包含以下核心属性:
- 顶点坐标描述模型局部空间的顶点位置坐标(x, y, z)。
- 法线信息定义顶点朝向,用于光照计算和表面平滑度。
- UV信息二维纹理映射坐标(u, v),范围[0,1],控制贴图在模型表面的分布。
- 切线向量与法线配合构建切线空间,用于法线贴图等高级渲染效果。
- 顶点颜色存储逐顶点颜色值,可用于特殊着色效果。
- 索引列表定义顶点连接顺序,优化绘制效率(减少重复顶点)
- 数据来源:
由建模工具(如Blender/Maya)导出时生成,随模型文件(.fbx/.obj)导入Unity。
程序化网格通过
Mesh类API动态设置(如mesh.vertices,mesh.uv)变换矩阵
矩阵数据由CPU计算并传递给GPU:
- 模型矩阵 Model Matrix(M) 模型局部坐标→世界坐标,由物体的
Transform组件(位置/旋转/缩放)计算得出。- 计算顺序:缩放 → 旋转 → 平移(SRT)
- 视图矩阵 View Matrix(V) 世界坐标→摄像机坐标,基于
Camera组件的位姿(位置/朝向/上方向)生成。- 计算原理:先逆平移(摄像机到原点),再逆旋转(对齐坐标轴)
- 投影矩阵 Projection Matrix(P) 摄像机坐标→齐次裁剪坐标,通过相机参数计算:
- 参数来源:FOV、近/远裁剪面、宽高比
- 透视投影(近大远小)或正交投影(等比例缩放)
Field of View (FOV):视角范围Near/Far Clipping Planes:近远裁剪平面Aspect Ratio:屏幕宽高比。
- MVP矩阵最终变换矩阵:
MVP = P × V × M - 计算主体与存储位置
矩阵类型 计算者 存储位置(GPU端) 访问方式(Shader) 模型矩阵 (M) Transform组件 (CPU计算) unity_ObjectToWorldUNITY_MATRIX_M视图矩阵 (V) 摄像机组件 (CPU计算) unity_MatrixVUNITY_MATRIX_V投影矩阵 (P) 摄像机投影参数 (CPU计算) unity_MatrixPUNITY_MATRIX_PMVP矩阵 Shader运行时组合 无独立存储 mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, pos)) - 计算时机
- CPU端:每帧渲染前更新(物体Transform或摄像机移动时)。
- GPU端:通过
UNITY_MATRIX_VP(视图投影矩阵)与UNITY_MATRIX_M(模型矩阵)在顶点着色器动态组合
- 优化机制
URP预计算
VP矩阵(视图投影联合矩阵),减少GPU计算量。使用
UnityObjectToClipPos内置函数直接完成MVP变换:hlsl
float4 clipPos = UnityObjectToClipPos(v.vertex); // 内部实现:mul(UNITY_MATRIX_VP, mul(UNITY_MATRIX_M, v.vertex))
- 模型矩阵 Model Matrix(M) 模型局部坐标→世界坐标,由物体的
灯光、材质参数
- 灯光参数
- 光源属性:位置、颜色、强度、衰减等,源自场景中的
Light组件。 - 阴影参数:阴影强度、分辨率,通过URP光源设置(如
UniversalAdditionalLightData)配置。
- 光源属性:位置、颜色、强度、衰减等,源自场景中的
- 材质数据
- Shader与材质属性:漫反射颜色、高光强度等,由
Material实例定义。 - 纹理贴图:通过材质绑定(如
_MainTex),从纹理资源加载。
- Shader与材质属性:漫反射颜色、高光强度等,由
数据传递流程:
应用阶段通过SetPassCall设置渲染状态(Shader/材质),并通过DrawCall提交图元列表
Batch:
- 把数据加载到显存,设置渲染状态,CPU调用GPU渲染的过程称之为一个Batch。
Unity URP渲染管线中的渲染状态和渲染命令的实现
一、渲染状态设置(SetPassCall)
ScriptableRenderer类
- 位于
UniversalRenderer.cs中,负责管理URP的默认渲染流程。 - 调用
EnqueuePass方法将渲染Pass(如DrawObjectsPass)加入队列。
- 位于
CommandBuffer类
- 通过
CommandBufferPool.Get获取实例,录制渲染指令。 - 关键方法:
csharp
cmd.SetRenderTarget()// 绑定渲染目标
cmd.SetGlobalTexture()// 设置全局纹理
cmd.SetViewProjectionMatrices()// 设置VP矩阵
- 通过
Material与Shader
- 材质状态通过
Material.SetPass方法设置,触发底层SetPassCall。 - URP通过
ShaderData类管理着色器变体(Variant)的切换。
- 材质状态通过
二、图元提交(DrawCall)
ScriptableRenderContext类
核心方法
Submit提交所有录制的CommandBuffer到GPU。调用链:
csharp
context.ExecuteCommandBuffer(cmd);// 执行指令
context.DrawRenderers()// 触发DrawCall
DrawingSettings与FilteringSettings
在
DrawObjectsPass.Execute中配置:csharp
var drawSettings = new DrawingSettings(...);// 指定Shader Pass和排序var filterSettings = new FilteringSettings(...);// 设置渲染队列和层级
context.DrawRenderers(...);// 最终提交
Graphics.DrawMesh
- 直接提交网格数据的备选API,绕过URP流程但效率较低。
三、关键脚本位置
| 功能 | 脚本文件 | 核心方法 |
|---|---|---|
| 渲染流程控制 | UniversalRenderer.cs |
AddRenderPasses, Execute |
| 指令录制 | CommandBuffer.cs |
Clear, DrawMesh, Blit |
| 材质状态管理 | Material.cs |
SetPass, SetShaderPassEnabled |
| 数据提交 | ScriptableRenderContext.cs |
Submit, DrawRenderers |
四、执行流程示例
csharp
// 在ScriptableRenderPass中实现
public override void Execute(ScriptableRenderContext context, ref RenderingData data) {
CommandBuffer cmd = CommandBufferPool.Get("CustomPass");
cmd.SetRenderTarget(...);// SetPassCall
cmd.DrawMesh(...);// DrawCall
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
Unity URP渲染管线中的应用阶段渲染命令队列及渲染队列实现
在Unity URP渲染管线的应用阶段,渲染命令队列包含一系列图形命令,主要用于调度和执⾏渲染操作,例如清除缓冲区、绘制几何体、设置材质和着色器参数、处理光源阴影,以及执行后处理效果。
这些命令通过ScriptableRenderContext接口进行管理,该接口作为C#代码与Unity底层图形引擎的桥梁,确保命令按序列化顺序提交GPU处理。队列内容包括:
- 缓冲区清除命令(如颜色缓冲和深度缓冲)。
- 几何体绘制命令(调用
DrawMesh或DrawProcedural)。 - 状态设置命令(如设置视口、混合模式)。
- 阴影贴图生成命令(针对动态光源)。
- 后处理Pass(如抗锯齿或景深应用)。这些命令在每帧的渲染循环中被动态生成和执行,以支持前向渲染策略和性能优化。
URP中的渲染队列实现主要由ScriptableRenderPass类完成,它定义了Pass的执行顺序和具体渲染逻辑。具体脚本流程如下:
渲染队列管理:
渲染队列(如
RenderQueueRange.opaque或RenderQueueRange.transparent)在ScriptableRenderPass的构造函数中指定,通过字段如renderPassEvent控制Pass的执行时机(例如在相机渲染前或后)。例如,一个基本的Pass脚本会继承自
ScriptableRenderPass,并在其Configure方法中设置队列优先级:这里,Execute方法包含具体命令队列的实现,使用CommandBuffer来录制命令(如cmd.ClearRenderTarget),并通过ScriptableRenderContext提交。csharp
public class CustomRenderPass : ScriptableRenderPass
{
public override void Configure(CommandBuffer cmd, RenderTextureDescriptor cameraTextureDescriptor)
{
// 设置队列范围为不透明对象
renderPassEvent = RenderPassEvent.BeforeRenderingOpaques;
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
// 执行命令,如绘制或清除
CommandBuffer cmd = CommandBufferPool.Get();
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
脚本集成:
- 在
ScriptableRenderer(如UniversalRenderer)中,渲染队列通过m_ActiveRenderPassQueue列表管理。 - Setup阶段调用
AddRenderPasses方法收集所有关联的ScriptableRenderPass实例(来自RendererFeature),并按事件顺序排序;Execute阶段遍历列表执行每个Pass的Execute方法。 - 例如,
UniversalRenderPipeline.Render方法驱动整个流程:此脚本位于URP核心程序集(如UniversalRenderPipeline.cs),依赖于UniversalRenderPipelineAsset提供配置
csharp
protected override void Render(ScriptableRenderContext context, List<Camera> cameras)
{
// 排序相机并逐个处理foreach (var camera in cameras)
{
var renderer = cameraData.renderer;
renderer.Execute(context, ref renderingData);// 执行Pass队列
}
}
在Unity URP中,ShaderLab配置的渲染状态(如剔除、深度测试、混合模式等)的处理流程
一、状态读取与存储机制
ShaderLab解析阶段
- URP通过
ShaderCompiler解析ShaderLab代码,将Cull、ZTest、Blend等指令转换为底层渲染状态标识符。 - 解析结果存储在
ShaderData结构中,包含渲染状态变体(Variant)和材质属性。
GPU状态设置阶段
- 运行时由
CommandBuffer录制指令(如cmd.SetRenderTarget、cmd.SetGlobalDepthBias),通过ScriptableRenderContext.Submit提交到GPU。 - 关键存储位置:
- 剔除模式:存于
RenderStateBlock.cullMode,通过DrawingSettings传递给DrawRenderers调用。 - 深度测试/写入:通过
DepthState结构(含ZWrite、ZTest)配置,最终写入GPU深度缓冲区。 - 混合模式:由
BlendState管理(含BlendOp、SrcFactor等参数),绑定到渲染管线状态。
- 剔除模式:存于
URP运行时管理
UniversalRenderer在AddRenderPasses阶段收集所有Pass的渲染状态,合并到RenderStateBlock。- 通过
MaterialPropertyBlock动态覆盖材质属性(如运行时修改_ZWrite)。
二、关键脚本与调用链
| 功能 | 脚本/类 | 核心方法 | 数据流向 |
|---|---|---|---|
| Shader解析 | ShaderCompiler |
CompileShader |
ShaderLab → ShaderData |
| 状态录制 | CommandBuffer |
SetRenderState |
CPU → GPU指令队列 |
| Pass执行 | DrawObjectsPass |
Execute |
通过DrawingSettings传递状态 |
| 动态修改 | MaterialPropertyBlock |
SetFloat/SetInt |
运行时覆盖Shader参数 |
三、使用示例(URP中动态修改深度测试)
hlsl
// ShaderLab中声明深度测试
SubShader {
Pass {
ZWrite On
ZTest LEqual
}
}
运行时读取:通过
Material.GetInt("_ZWrite")获取状态。动态修改:
csharp
var block = new MaterialPropertyBlock();
block.SetInt("_ZWrite", 0);// 禁用深度写入
renderer.SetPropertyBlock(block);
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,)
【渲染流水线】[应用阶段]-[渲染命令队列]以UnityURP为例的更多相关文章
- Unity Shader 之 渲染流水线
Unity Shader 之渲染流水线 什么是渲染流水线 一个渲染流程分成3个步骤: 应用阶段(Application stage) 几何阶段(Geometry stage) 光栅化阶段(Raster ...
- Shader 入门笔记(二) CPU和GPU之间的通信,渲染流水线
渲染流水线 1)应用阶段(CPU处理) 首先,准备好场景数据(摄像机位置,视锥体,模型和光源等) 接着,做粗粒度剔除工作. 最后,设置好每个模型的渲染状态(使用的材质,纹理,shader等) 这一阶段 ...
- Unity Shader入门精要学习笔记 - 第2章 渲染流水线
来源作者:candycat http://blog.csdn.net/candycat1992/article/ 2.1 综述 渲染流水线的最终目的在于生成或者说是渲染一张二维纹理,即我们在电脑屏 ...
- Unity 渲染流水线 :CPU与GPU合作创造的艺术wfd
前言 对于Unity渲染流程的理解可以帮助我们更好对Unity场景进行性能消耗的分析,进而更好的提升场景渲染的效率,最后提升游戏整体的性能表现 Unity的游戏画面的最终的呈现是由CPU与GPU相互配 ...
- 《UnityShader入门精要》学习笔记之渲染流水线
第一种分类方式: 图形管道(如下7步): 顶点数据 : 由3D模型传递的三角形网格 顶点着色 : 编写CG程序对各个顶点进行着色 生成几何图元 : 连接特定的顶点生成几何图元,例如连接三个顶点生成一个 ...
- Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线
原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第五章:渲染流水线 学习目标 了解几个用以表达真实场景的标志和2D图像 ...
- 移动端 像素渲染流水线与GPU Hack
什么是 像素渲染流水线 web页面你所写的页面代码是如何被转换成屏幕上显示的像素的.这个转换过程可以归纳为这样的一个流水线,包含五个关键步骤: 1.JavaScript:一般来说,我们会使用JavaS ...
- 基于OpenGL编写一个简易的2D渲染框架-08 重构渲染器-整体架构
事实上,前面编写的渲染器 Renderer 非常简陋,虽然能够进行一些简单的渲染,但是它并不能满足我们的要求. 当渲染粒子系统时,需要开启混合模式,但渲染其他顶点时却不需要开启混合模式.所以同时渲染粒 ...
- Android 颜色渲染(三) Shader颜色渲染
版权声明:本文为博主原创文章,未经博主允许不得转载. 相信看过在上一篇中提到的三篇文章后,大家已经对颜色处理方面有更深的体会. 之前讲到颜色渐变的效果, 具体怎么做呢,这就需要应用颜色渲染. 首先要介 ...
- 老李推荐:第6章6节《MonkeyRunner源码剖析》Monkey原理分析-事件源-事件源概览-命令队列
老李推荐:第6章6节<MonkeyRunner源码剖析>Monkey原理分析-事件源-事件源概览-命令队列 事件源在获得字串命令并把它翻译成对应的MonkeyEvent事件后,会把这些 ...
随机推荐
- WPF 用 DrawingBrush实现图形的平铺
WPF平铺图像,一般用到 DrawingBrush 来实现对图形.图形的平铺,查阅了 微软官方文档的 DrawingBrush 属性 创建一个 DrawingBrush,其中: TileMode=& ...
- 探秘Transformer系列之(35)--- 大模型量化基础
探秘Transformer系列之(35)--- 大模型量化基础 目录 探秘Transformer系列之(35)--- 大模型量化基础 0x00 概述 0x01 outlier 1.1 定义 1.2 特 ...
- kubernetes部署kafka集群
一.kafka介绍 kafka是一个分布式.多副本.多订阅者.分区的,基于zoopkeeper协调的分布式日志系统.其主要特点为: 1.以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上 ...
- Controller接收前端参数
四个常用的Mapping @PutMapping: 和PostMapping作用等同,都是用来向服务器提交信息.如果是添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMap ...
- QA - RAG智能问答系统中的文档切片与实现原理
引言 在现代企业知识管理系统中,智能问答系统正发挥着越来越重要的作用.GC-QA-RAG系统作为葡萄城技术栈中的重要组成部分,其核心功能是通过对文档内容进行智能切片和向量化存储,实现对技术文档的高效检 ...
- Docker + CentOS 部署 Zookeeper 集群 + Kubernetes Operator 自动化运维方案
环境说明 主机 IP 主机名 节点角色 数据目录 Kubernetes 节点标签 192.168.10.100 zk1 Master /opt/zookeeper/data zk-cluster=tr ...
- nfs安装与使用
前言 NFS的全称是Network File System(网络文件系统): 通过网络让不同的设备间共享文件或者目录. 如:有两台服务器 Name IP 备注 A 192.168.1.1 A机器的硬盘 ...
- git所有分支和提交搜索
git rev-list --all | xargs git grep "xxx" git rev-list:打印所有节点(commit头),其中后边可以跟一个点,也可以跟两个点, ...
- 前端开发系列064-网络篇之FormData基本使用
FormData 简单介绍 FormData是Ajax 2.0-XMLHttpRequest Level 2 提供的一个接口对象,可以使用该对象来模拟和处理表单并方便的进行文件上传操作. consol ...
- MySQL 13 为什么表数据删掉一半,表文件大小不变?
一个InnoDB表包含两部分:表结构定义和数据.在MySQL 8.0版本前,表结构存在以.frm为后缀的文件里.之后的版本允许把表结构定义放在系统数据表中.由于表结构定义占用空间很小,所以主要讨论表数 ...