unity绘制管道_Unity可编程渲染管线(SRP)教程:一、自定义管线

本文是Unity可编程渲染管线教程的第一部分,介绍了如何创建和设置自定义管线资产,包括替换默认渲染管线、创建管线实例、处理渲染上下文、剔除和排序,以及解决内存管理和编辑体验。通过实现IRenderPipeline接口,逐步构建了一个能够绘制Unlit图形的最小渲染管线,同时探讨了如何处理天空盒、相机、命令缓冲和剔除操作。在后续教程中,将进一步扩展自定义管线以支持光照、阴影等高级特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

控制渲染

创建pipeline asset 和 instance.

剔除、过滤、排序、渲染.

保持内存清洁.

提供良好的编辑体验.

这是Unity scriptable render pipeline系列教程的第一部分。本教程假设你首先通过了Basics系列教程和Procedural Grid教程。Rendering系列的头几部分也很有帮助。

本教程使用Unity 2018.3.0f2完成。创建一个Pipeline

渲染任何东西Unity都需要明确哪些形状、何处、何时以及使用什么设置。这些可以变得非常复杂取决于涉及到多少效果。光源、阴影、半透明、图像效果、体积效果以及等等都需要用正确的顺序处理,以获得最终的图像。这个过程被称之为渲染管线。

Unity 2017 支持两种预定义渲染管线,一种是前向渲染,另一种是延迟渲染。也仍然支持Unity 5中引入的旧延迟渲染方法。这种管线是固定的。你可以开启、关闭或者覆盖管线中某些部分,但不可以彻底偏离它的设计。

Unity 2018 添加了可编程渲染管线的支持,使得从头设计管线成为可能,尽管你仍然需要依赖Unity来完成许多单独的步骤,例如剔除。Unity 2018引入了两种使用这种新方法的管线,轻量级渲染管线和高分辨率渲染管线。两种管线仍处于预览阶段并且可编程渲染管线API依然被标记为实验技术。但是在这一点上对我们来说足够稳定可以继续创建并创建我们自己的管线。

在这个教程中我们会设置一个绘制Unlit图形的最小渲染管线。一旦起作用了,我们可以在之后的教程中扩展我们的管线,添加光照、阴影、以及更多的高级特性。

1.1 项目设置

打开Unity 2018并创建一个新项目。我使用的是Unity 2018.2.9f1,但是任何2018.2版本或者更新版应该也可以使用。创建一个Standard 3D项目并禁用analytics。我们会创建我们自己的管线,所以不选择任何管线选项。

项目打开后,由Window/Pakage Manager打开包管理器,并且移除所有默认包含的包,因为我们不需要它们。只保留不可以被移除的Package Manager UI。初始的项目

我们要在线性色彩空间下工作,但是Unity 2018依然默认使用gamma空间。所以由Edit/Project Setting/Player到player setting中,然后将Other Setting部分中的色彩空间切换到Linear。线性色彩空间

我们需要几个简单的材质去测试我们的管线。我创建了四种材质。第一种,默认的standard opaque材质带有红色albedo。第二种,一样的材质但是Rendering Mode设置为Transparent以及蓝色的albedo带有减少的alpha。第三种,使用Unlit/Color shader并且颜色设置为黄色的材质。最后一种使用Unlit/Transparent shader并不做任何改变,因此显示为纯白色。测试材质

使用一些object填充场景,让它们用完所有的四种材质。

场景显示四种材质

1.2 Pipeline Asset

现在,Unity使用默认的前向渲染管线。要使用自定义管线,我们需要在grahics settings中选择,可以由Edit/Project Setting/Graphics找到。

使用默认管线

要设置我们自己的管线,我们需要分配一个pipeline asset到Scriptable Render Pipeline Settings字段。这类asset需要扩展RenderPipelineAsset,这是一种ScriptableObject类型。

为我们的自定义pipeline asset创建一个新脚本。我们将简单地命名我们的管线为My Pipeline。这个asset类型将因此成为MyPipelineAsset并且需要扩展RenderPipelineAsset,它被定义在UnityEngine.Experimental.Rendering命名空间中。using UnityEngine;using UnityEngine.Experimental.Rendering;public class MyPipelineAsset : RenderPipelineAsset {}它会一直在experimental命名空间中吗?它会在某个时刻被移出experimental命名空间,到UnityEngine.Rendering或者其他命名空间。当这种情况发生时,只需要更新using语句,除非API也发生了改变。

pipeline asset的主要目的是给Unity一个途径去获取负责渲染的管线对象实例。asset它本身只是一个句柄和存放管线设置的地方。我们目前还没有任何设置,所以我们要做的是给Unity一个途径去获取我们的管线对象实例。这个通过重载InternalCreatePipeline方法来实现。但是我们还没有定义我们的管线对象,所以此时我们将仅返回null。

InternalCreatePipeline返回值类型是IRenderPipeline。类型名的I前缀表示它是接口类型。public class MyPipelineAsset : RenderPipelineAsset {protected override IRenderPipeline InternalCreatePipeline () {return null;}}什么是接口?接口就像一个类,除了定义一个功能合同且不提供它的实现。它只定义属性、事件、索引器和方法签名,它们都是被定义公开的。任何扩展接口的类型都要求包含接口定义的实现。惯例是在接口名前加个I前缀。因为接口不包含具体的实现,所以类甚至结构体可以扩展多个接口。如果多个接口碰巧定义了相同的东西,它们只是同意功能应该存在。在类中是不可以的即使是抽象类,因为这个可能导致实现冲突。

现在我们需要为我们的项目添加一个这种类型的asset。要实现这点,添加CreateAssetMenu特性到MyPipelineAsset。[CreateAssetMenu]public class MyPipelineAsset : RenderPipelineAsset {}

这在Asset/Create菜单中添加了个入口。让我们整理一下,把他放到Rendering的子菜单中。我们通过设置特性的menuName属性为Rendering/My Pipeline来完成。这个属性在可以被直接设置在特性类型之后的圆括号中。[CreateAssetMenu(menuName = "Rendering/My Pipeline")]public class MyPipelineAsset : RenderPipelineAsset {}

使用新菜单项添加这个asset到项目,命名为My Pipeline。Pipeline asset及其脚本

然后把它分配到Scriptable Render Pipeline Settings。

使用中的Asset

我们现在已经替换了默认的管线,更改了一些东西。首先,graphics setting中的大量选项不见了,Unity也在信息面板中提到了这些设置。其次,我们绕过了默认管线并不提供有效的替换,因此不会进行任何渲染。尽管,场景窗口仍然显示天空盒,但是游戏窗口、场景窗口和材质预览不再起作用,如果你由Window/Analysis/Frame Debugger打开帧调试器,并且启用它,你会看见确实没有在游戏窗口中绘制任何东西。

1.3 管线实例

创建一个有效的管线,我们需要提供一个实现IRenderPipeline并负责渲染流程的对象实例。所以为此创建一个类将其命名为MyPipeline。using UnityEngine;using UnityEngine.Experimental.Rendering;public class MyPipeline : IRenderPipeline {}

尽管我们可以实现由自己IRenderPipeline,但是更方便的是扩展RenderPipeline类。这个类型已经提供一个IRenderPipeline我们可以自己构建的实现。public class MyPipeline : RenderPipeline {}

现在我们可以在InternalCreatePipeline中返回一个MyPipeline的新实例。这意味着我们在技术上有了一个有效的管线,尽管这依然不能渲染任何东西。protected override IRenderPipeline InternalCreatePipeline () {return new MyPipeline();}

2. 渲染

管线对象负责渲染每一帧。Unity会根据上下文以及激活的相机调用管线的Render方法。这是针对游戏窗口的,也适用于场景窗口和编辑器中的材质预览。这需要我们适当地配置,找到需要渲染的内容,并且按正确的顺序处理每个操作。

2.1 上下文

RenderPipeline包含了定义在IRenderPipeline接口中的Render方法的实现。它第一个参数是渲染上下文,这是ScriptableRenderContext结构,作为native code的外在表现。这第二个参数

### Unity 内置渲染管线与 URP (Universal Render Pipeline) 的区别 #### 渲染架构差异 Unity 内置渲染管线采用较为传统的单通道或多通道延迟渲染方式,其灵活性较低。相比之下,URP 是基于 Scriptable Render Pipeline(SRP),允许开发者自定义渲染流程中的各个阶段[^1]。 #### 性能优化特性 对于移动设备和其他资源受限平台而言,URP 提供了更高效的性能表现。这是因为 URP 支持更低级别的硬件访问控制以及更好的批处理能力,从而减少了绘制调用次数并提高了帧率稳定性[^4]。 #### Shader 和材质支持 在内置渲染管线中使用的着色器主要依赖于 Surface Shaders 或者 Handwritten Vertex/Pixel Shaders 。然而,在 URP 下则完全迁移到 HLSL 并引入了新的 Material Properties ,这不仅简化了开发过程还增强了跨平台兼容性。 #### 特殊效果实现 当涉及到复杂视觉特效如屏幕空间环境光遮蔽(Ambient Occlusion)时,两者都提供了相应的解决方案。但在具体实现上有所区别;例如,在 URP 中可以通过编写自定义 Passes 来增强此类功能的效果质量[^3]。 ```csharp // 示例:如何在个简单的 URP shader 中添加 AO 效果 Shader "Custom/AOExample" { SubShader { Tags { "RenderType"="Opaque" } Pass { Name "AO" HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; }; struct Varyings { float4 posHCS : SV_POSITION; float2 uv : TEXCOORD0; }; sampler2D _MainTex; Varyings vert(Attributes input) { Varyings output; output.posHCS = TransformObjectToHClip(input.positionOS); output.uv = input.uv; return output; } half4 frag(Varyings input) : SV_Target { // 假设我们已经有了个可以获取 SSAO 数据的方法 GetScreenSpaceAmbientOcclusion() half aoValue = GetScreenSpaceAmbientOcclusion(input.uv); // 应用 AO 到最终颜色输出 half4 color = tex2D(_MainTex, input.uv); color.rgb *= lerp(1.0, aoValue, 0.75); return color; } ENDHLSL } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值