https://docs.unity3d.com/Manual/ScriptableRenderPipeline.html
可编程渲染管线(SRP)是Unity内置渲染管线的替代方法。
Unity提供了HDRP(高清渲染管线)和URP(通用渲染管线)两种模板
-
更自由灵活的自定义管线
使用SRP,可以通过C#脚本控制和定制渲染 。 这样,您可以根据需要稍微修改或完全构建和自定义渲染管道。
与内置的Unity渲染管道相比,SRP提供了更多的粒度和自定义选项。 可以使用一种预先构建的SRP来满足您的特定需求。
-
着色器不同
使用SRP与使用内置的Unity渲染管道不同。 例如,预建的SRP使用自己的着色器库。 这是因为内置渲染管道中的Lit着色器和自定义Lit着色器不适用于SRP。 您可以将内置的Lit着色器升级到URP和HDRP。
LWRP 在Unity2019.3版本后已更名为Universal Render Pipleline,通用渲染管线。可在创建工程面板直接看到URP的工程模板
-
安装
Unity已构建了两个可编写脚本的渲染管道:高清晰度渲染管道(HDRP)和轻量级渲染管道(URP)。 每个渲染管道都针对一组特定的用例场景和硬件需求。 预构建的渲染管道可作为项目模板使用。
URP项目模板包含了一个示例演示
注意:HDRP和URP彼此不兼容,因为它们使用不同的照明模型。 您的项目必须使用其中一个。 但是,您可以在同一渲染管道中使用不同的资源。 这意味着可以通过在不同资产之间交换来测试不同的设置,而不用更改各个设置。
两个关键元素:
使用SRP必须在工程中包含两个关键脚本
-
渲染管线实例(Render Pipeline Instance)
- 定义渲染管线的功能
- 继承自 RenderPipeline,
- 重写
Render()
函数
using UnityEngine;
using UnityEngine.Rendering;
public class ExampleRenderPipelineInstance : RenderPipeline
{
// Use this variable to a reference to the Render Pipeline Asset that was passed to the constructor
private ExampleRenderPipelineAsset renderPipelineAsset;
// The constructor has an instance of the ExampleRenderPipelineAsset class as its parameter.
public ExampleRenderPipelineInstance(ExampleRenderPipelineAsset asset) {
renderPipelineAsset = asset;
}
protected override void Render(ScriptableRenderContext context, Camera[] cameras) {
// This is an example of using the data from the Render Pipeline Asset.
Debug.Log(renderPipelineAsset.exampleString);
// This is where you can write custom rendering code. Customize this method to customize your SRP.
}
}
-
渲染管线配置资产 (Render Pipeline Asset)
- 存储管线配置数据,并通过资产创建一个管线实例
- 继承自 RenderPipelineAsset , 重写
CreatePipeline()
函数
using UnityEngine;
using UnityEngine.Rendering;
// The CreateAssetMenu attribute lets you create instances of this class in the Unity Editor.
[CreateAssetMenu(menuName = "Rendering/ExampleRenderPipelineAsset")]
public class ExampleRenderPipelineAsset : RenderPipelineAsset
{
// This data can be defined in the Inspector for each Render Pipeline Asset
public Color exampleColor;
public string exampleString;
// Unity calls this method before rendering the first frame.
// If a setting on the Render Pipeline Asset changes, Unity destroys the current Render Pipeline Instance and calls this method again before rendering the next frame.
protected override RenderPipeline CreatePipeline() {
// Instantiate the Render Pipeline that this custom SRP uses for rendering, and pass a reference to this Render Pipeline Asset.
// The Render Pipeline Instance can then access the configuration data defined above.
return new ExampleRenderPipelineInstance(this);
}
}
- 通过在工程图形设置里指定管线配置文件,来设置工程的渲染管线
也可以在质量设置里对不同品质指定不同的管线配置文件
可编程渲染上下文 ScriptableRenderContext
- c#代码与底层图形代码的沟通接口
- 通过上下文组织和执行 渲染命令.
- 使用 ScriptableRenderContext.ExecuteCommandBuffer 向SRP传递 CommandBuffers
- 直接执行Context封装的API,如Cull或DrawRenderers
using UnityEngine;
using UnityEngine.Rendering;
public class ExampleRenderPipeline : RenderPipeline
{
public ExampleRenderPipeline() {
}
protected override void Render(ScriptableRenderContext context, Camera[] cameras) {
// Create and schedule a command to clear the current render target
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, true, Color.red);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// Tell the Scriptable Render Context to tell the graphics API to perform the scheduled commands
context.Submit();
}
}
另一种执行渲染命令的方法是直接执行CommandBuffers: Graphics.ExecuteCommandBuffer
入口和回调
- SPR的主入口是
RenderPipeline.Render()
函数 - RenderPipelineManager 可以处理一系列委托
beginFrameRendering
beginCameraRendering
endCameraRendering
endFrameRendering
实例
默认内置管线
⬇
使用上面例子的管线后,可以看到只剩一个缓冲清理操作了。
渲染循环的构建
- 1·清除渲染目标
// Create and schedule a command to clear the current render target
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, true, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// Instruct the graphics API to perform all scheduled commands
context.Submit();
- 2·剔除
foreach (Camera camera in cameras)
{
// Get the culling parameters from the current Camera
// 从相机中获取剔除参数
camera.TryGetCullingParameters(out var cullingParameters);
// Use the culling parameters to perform a cull operation, and store the results
//使用剔除参数执行剔除,并保存结果
var cullingResults = context.Cull(ref cullingParameters);
}
- 3·绘制
- 创建并设置过滤设置(FilteringSettings):过滤剔除结果
- 创建并设置绘制设置(DrawingSettings):描述哪些几何体需要绘制已经绘制的方式
- (可选)重写渲染状态设置
- 调用 ScriptableRenderContext.DrawRenderers进行绘制
/*
This is a simplified example of a custom Scriptable Render Pipeline.
It demonstrates how a basic render loop works.
It shows the clearest workflow, rather than the most efficient runtime performance.
*/
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);
//释放CommandBuffer
cmd.Release();
// 遍历所有相机
foreach (Camera camera in cameras)
{
//从相机中获取剔除参数
camera.TryGetCullingParameters(out var cullingParameters);
// 使用剔除参数执行剔除操作,并保存结果
var cullingResults = context.Cull(ref cullingParameters);
// Update the value of built-in shader variables, based on the current Camera
// 用相机更新shader内置变量
context.SetupCameraProperties(camera);
// Tell Unity which geometry to draw, based on its LightMode Pass tag value
// 创建ShaderTagId,告诉Unity要绘制的几何体:基于LightMode设置
ShaderTagId shaderTagId = new ShaderTagId("ExampleLightModeTag");
// Tell Unity how to sort the geometry, based on the current Camera
// 创建排序设置,基于相机
var sortingSettings = new SortingSettings(camera);
// Create a DrawingSettings struct that describes which geometry to draw and how to draw it
// 使用ShaderTagId和排序设置构建DrawingSettings
DrawingSettings drawingSettings = new DrawingSettings(shaderTagId, sortingSettings);
// Tell Unity how to filter the culling results, to further specify which geometry to draw
// Use FilteringSettings.defaultValue to specify no filtering
// 剔除结果的过滤设置
FilteringSettings filteringSettings = FilteringSettings.defaultValue;
// Schedule a command to draw the geometry, based on the settings you have defined
//组织渲染命令进行绘制
context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);
// Schedule a command to draw the Skybox if required
// 绘制天空盒(如果需要)
if (camera.clearFlags == CameraClearFlags.Skybox && RenderSettings.skybox != null)
{
context.DrawSkybox(camera);
}
// Instruct the graphics API to perform all scheduled commands
context.Submit();
}
}
}