渲染循环是指在单一帧中发生的所有渲染操作的术语。本页面包含有关在基于 Unity 可编程渲染管线的自定义渲染管线中创建简单渲染循环的信息。
本页面上的代码示例演示使用可编程渲染管线的基本原则。可以使用此信息构建自己的自定义可编程渲染管线,或了解 Unity 的预构建可编程渲染管线如何工作。
开始为渲染循环编写代码之前,必须准备好项目。
步骤如下所示:
在可编程渲染管线中,使用 LightMode
通道标签确定如何绘制几何体。有关通道标签的更多信息,请参阅 ShaderLab:向通道分配标签。
此任务演示如何创建非常简单的无光照 Shader 对象,其 LightMode 通道标签值为 ExampleLightModeTag
。
// 这定义一个与自定义可编程渲染管线兼容的简单无光照 Shader 对象。
// 它应用硬编码颜色,并演示 LightMode 通道标签的使用。
// 它不与 SRP Batcher 兼容。
Shader "Examples/SimpleUnlitColor"
{
SubShader
{
Pass
{
// LightMode 通道标签的值必须与 ScriptableRenderContext.DrawRenderers 中的 ShaderTagId 匹配
Tags { "LightMode" = "ExampleLightModeTag"}
HLSLPROGRAM
#pragma vertex vert
#pragma fragment frag
float4x4 unity_MatrixVP;
float4x4 unity_ObjectToWorld;
struct Attributes
{
float4 positionOS : POSITION;
};
struct Varyings
{
float4 positionCS : SV_POSITION;
};
Varyings vert (Attributes IN)
{
Varyings OUT;
float4 worldPos = mul(unity_ObjectToWorld, IN.positionOS);
OUT.positionCS = mul(unity_MatrixVP, worldPos);
return OUT;
}
float4 frag (Varyings IN) : SV_TARGET
{
return float4(0.5,1,0.5,1);
}
ENDHLSL
}
}
}
要测试渲染循环是否可正常工作,必须创建要渲染的内容。此任务演示如何在场景中放置使用在上一个任务中创建的 SRP 兼容着色器的游戏对象。
准备的最后阶段是创建自定义 SRP 所需的基本源文件,并告知 Unity 开始使用自定义 SRP 进行渲染。
RenderPipeline
的类和一个兼容渲染管线资源。在简单渲染循环中,基本操作有:
清除意味着移除在最后一帧期间绘制的内容。渲染目标通常是屏幕;但是,也可以渲染到纹理以创建“画中画”效果。这些示例演示如何渲染到屏幕,这是 Unity 的默认行为。
要清除可编程渲染管线中的渲染目标,请执行以下操作:
Clear
命令配置 CommandBuffer
。CommandBuffer
添加到 ScriptableRenderContext
上的命令队列;为此,请调用 ScriptableRenderContext.ExecuteCommandBuffer。ScriptableRenderContext
上的命令队列;为此,请调用 ScriptableRenderContext.Submit。与所有可编程渲染管线操作一样,使用 RenderPipeline.Render 方法作为此代码的入口点。此示例代码演示如何执行此操作:
/*
这是自定义可编程渲染管线的简化示例。
它演示基本渲染循环的工作方式。
它演示最清晰的工作流程,而不是最高效的运行时性能。
*/
using UnityEngine;
using UnityEngine.Rendering;
public class ExampleRenderPipeline : RenderPipeline {
public ExampleRenderPipeline() {
}
protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
// 创建并调度命令以清除当前渲染目标
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// 指示图形 API 执行所有调度的命令
context.Submit();
}
}
剔除是过滤掉对摄像机不可见的几何体的过程。
要在可编程渲染管线中进行剔除,请执行以下操作:
ScriptableCullingParameters
结构的值。CullingResults
结构中。此示例代码扩展了上面的示例,演示如何清除渲染目标,然后执行剔除操作:
/*
这是自定义可编程渲染管线的简化示例。
它演示基本渲染循环的工作方式。
它演示最清晰的工作流程,而不是最高效的运行时性能。
*/
using UnityEngine;
using UnityEngine.Rendering;
public class ExampleRenderPipeline : RenderPipeline {
public ExampleRenderPipeline() {
}
protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
// 创建并调度命令以清除当前渲染目标
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// 遍历所有摄像机
foreach (Camera camera in cameras)
{
// 从当前摄像机获取剔除参数
camera.TryGetCullingParameters(out var cullingParameters);
// 使用剔除参数执行剔除操作,并存储结果
var cullingResults = context.Cull(ref cullingParameters);
}
// 指示图形 API 执行所有调度的命令
context.Submit();
}
}
绘制是指示图形 API 使用给定设置绘制一组给定几何体的过程。
要在 SRP 中进行绘制,请执行以下操作:
CullingResults
结构中。此示例代码基于上面的示例进行构建,演示如何清除渲染目标,执行剔除操作,然后绘制生成的几何体:
/*
这是自定义可编程渲染管线的简化示例。
它演示基本渲染循环的工作方式。
它演示最清晰的工作流程,而不是最高效的运行时性能。
*/
using UnityEngine;
using UnityEngine.Rendering;
public class ExampleRenderPipeline : RenderPipeline {
public ExampleRenderPipeline() {
}
protected override void Render (ScriptableRenderContext context, Camera[] cameras) {
// 创建并调度命令以清除当前渲染目标
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// 遍历所有摄像机
foreach (Camera camera in cameras)
{
// 从当前摄像机获取剔除参数
camera.TryGetCullingParameters(out var cullingParameters);
// 使用剔除参数执行剔除操作,并存储结果
var cullingResults = context.Cull(ref cullingParameters);
// 基于当前摄像机,更新内置着色器变量的值
context.SetupCameraProperties(camera);
// 基于 LightMode 通道标签值,向 Unity 告知要绘制的几何体
ShaderTagId shaderTagId = new ShaderTagId("ExampleLightModeTag");
// 基于当前摄像机,向 Unity 告知如何对几何体进行排序
var sortingSettings = new SortingSettings(camera);
// 创建描述要绘制的几何体以及绘制方式的 DrawingSettings 结构
DrawingSettings drawingSettings = new DrawingSettings(shaderTagId, sortingSettings);
// 告知 Unity 如何过滤剔除结果,以进一步指定要绘制的几何体
// 使用 FilteringSettings.defaultValue 可指定不进行过滤
FilteringSettings filteringSettings = FilteringSettings.defaultValue;
// 基于定义的设置,调度命令绘制几何体
context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);
// 在需要时调度命令绘制天空盒
if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
{
context.DrawSkybox(camera);
}
// 指示图形 API 执行所有调度的命令
context.Submit();
}
}
}
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.