本文从内容上是继承自Unity的官方说明文档。添加了部分自己对SRP的认识。
srp asset是srp在编辑器下的一种序列后的资源文件。类似的,我们在导入lwrp之后,可以在project文件下创建一个lwrp的资源文件,选中后在inspector中会出现如下界面:
这里创建的就是srp asset。而srp asset所对应的对象就是srp instance。Asset的作用可以看成是srp的设置界面,其设置的参数将会传入到srp instance。但是这里并不是传入那么简单,其实是重新创建了一个新的instance。
srp asset修改的是srp instance的参数,那对应srp instance是什么?
从名字既可知道,srp instance是srp的一种实例,是srp的逻辑的实现对象。我们在srp asset中设置的参数将会输入我们设置的接口,并且按照参数生产新的instance。
在srp instance中我们需要声明自定义渲染管线的逻辑,从而实现自定义效果。在其中可实现:
srp asset与其他unity asset资源等同,可通过AssetDatabase.CreateAsset接口创建。其实也就是去序列化一个类的对象。
下面给出最简srp脚本:
[ExecuteInEditMode]
public class BasicAssetPipe : RenderPipelineAsset
{
public Color clearColor = Color.green;
#if UNITY_EDITOR
// Call to create a simple pipeline
[UnityEditor.MenuItem("SRP-Demo/01 - Create Basic Asset Pipeline")]
static void CreateBasicAssetPipeline()
{
var instance = ScriptableObject.CreateInstance<BasicAssetPipe>();
UnityEditor.AssetDatabase.CreateAsset(instance, "Assets/BasicAssetPipe.asset");
}
#endif
// Function to return an instance of this pipeline
protected override IRenderPipeline InternalCreatePipeline()
{
return new BasicPipeInstance(clearColor);
}
}
其中,InternalCreatePipeline
是重写自接口RenderPipelineAsset
,[ExecuteInEditMode]
保证更新函数能够在编辑器模式下执行。该函数会在每次对srp asset进行修改后,创建出新的srp instance。这里返回的是自定义的BasicPipeInstance
对象。
internal class BasicPipeInstance : RenderPipeline
{
private Color screenColor;
private bool stereoEnable = false;
public BasicPipeInstance(Color screenColor)
{
this.screenColor = screenColor;
}
public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{
base.Render(renderContext, cameras);
//command
var cmd = new CommandBuffer();
//cmd.DrawRenderer(renderContext, new Material());
cmd.ClearRenderTarget(true, true, screenColor);//1
renderContext.ExecuteCommandBuffer(cmd);//2
cmd.Release();
//clear screen
//end command
renderContext.Submit();
}
}
}
类中只是简单实现了清屏效果,在创建asset之后,屏幕会跟随设置的颜色进行变化。这里就体现了srp与传统rp之间的区别。传统rp是一个黑盒,我们只能通过shader去处理物体的渲染效果,而srp能够通过unity给出的接口自定义渲染流程和处理渲染的效果。相当于开了底层的接口,我们能够更好的实现我们想要的效果,而不受rp的限制。
public override void Render(ScriptableRenderContext renderContext, Camera[] cameras)
{
base.Render(renderContext, cameras);
// clear depth buffer
//context才是渲染管线的本体
foreach (var camera in cameras)
{
// Culling
ScriptableCullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
CullResults cull = CullResults.Cull(ref cullingParams, renderContext);
// Setup camera for rendering (sets render target, view/projection matrices and other
// per-camera built-in shader variables).
renderContext.SetupCameraProperties(camera);
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, false, screenColor);
renderContext.ExecuteCommandBuffer(cmd);
cmd.Release();
// Draw opaque objects using BasicPass shader pass
var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
settings.sorting.flags = SortFlags.CommonOpaque;
var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
renderContext.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);
// Draw skybox
renderContext.DrawSkybox(camera);
renderContext.Submit();
}
}
在官方文档中没有提及摄像机遍历部分。对于srp会将场景和编辑器下的每个相机都会输出(除了game场景还有scene窗口),因此srp的编写也会影响到scene窗口。
在渲染中首先会根据相机和3d对象进行剔除,获取到剔除后需要渲染的对象
// Culling
ScriptableCullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
CullResults cull = CullResults.Cull(ref cullingParams, renderContext);
具体剔除规则后面更新
然后对渲染方式进行设置,并渲染结果
var settings = new DrawRendererSettings(camera, new ShaderPassName("BasicPass"));
settings.sorting.flags = SortFlags.CommonOpaque;
var filterSettings = new FilterRenderersSettings(true) { renderQueueRange = RenderQueueRange.opaque };
renderContext.DrawRenderers(cull.visibleRenderers, ref settings, filterSettings);
这里会使用到new ShaderPassName("BasicPass"));
语句,注意这里的参数BasicPass
需要填写shader中的lightmode
对应的值,而不是pass的name。
测试工程链接在这里