上下文会延迟实际渲染,直到被提交。在此之前,我们对其进行配置并向其添加命令以供稍后执行。某些任务(例如绘制天空盒)可以通过专用方法发出,但其他命令必须通过单独的命令缓冲区间接发出。我们需要这样的缓冲区来绘制场景中的其他几何体。
为了获得缓冲区,我们必须创建一个新的CommandBuffer对象实例。我们只需要一个缓冲区,因此默认创建一个缓冲区CameraRenderer并将对其的引用存储在字段中。还要为缓冲区命名,以便我们可以在帧调试器中识别它。
conststring bufferName = "Render Camera";
CommandBuffer buffer = newCommandBuffer {name = bufferName};
我们可以使用命令缓冲区来注入分析器示例,这些示例将显示在分析器和帧调试器中。这是通过在适当的点调用BeginSample和EndSample来完成的,在我们的例子中,两种方法必须提供相同的示例名称,为此我们将使用缓冲区的名称。
void Setup () {
buffer.BeginSample(bufferName);context.SetupCameraProperties(camera);}void Submit () {buffer.EndSample(bufferName);context.Submit();}
要执行缓冲区,请使用ExecuteCommandBuffer缓冲区作为参数调用上下文。这会从缓冲区复制命令但不会清除它,如果我们想重用它,我们必须在之后显式地执行此操作。因为执行和清除总是一起完成,所以添加一个同时执行这两项操作的方法很方便。
void Setup () {
buffer.BeginSample(bufferName);ExecuteBuffer();context.SetupCameraProperties(camera);}void Submit () {buffer.EndSample(bufferName);ExecuteBuffer();context.Submit();}void ExecuteBuffer () {context.ExecuteCommandBuffer(buffer);buffer.Clear();}
现在Camera.RenderSkyBox是嵌套在Render Camera里面的。

渲染相机
无论我们绘制什么,最终都会渲染到相机的渲染目标,默认情况下是帧缓冲区,但也可以是渲染纹理。之前绘制到该目标的任何内容仍然存在,这可能会干扰我们现在渲染的图像。为了保证正确的渲染,我们必须清除渲染目标以摆脱其旧内容。这是通过调用ClearRenderTarget属于该Setup方法的命令缓冲区来完成的。
CommandBuffer.ClearRenderTarget需要至少三个参数。前两个表示是否应清除深度和颜色数据,两者都是如此。第三个参数是用于清除的颜色,我们将使用Color.clear。
void Setup () {
buffer.BeginSample(bufferName);buffer.ClearRenderTarget(true, true, Color.clear);ExecuteBuffer();context.SetupCameraProperties(camera);}

清除带有嵌套的层
帧调试器现在显示Draw GL清除操作的内容,它嵌套在附加级别中Render Camera。发生这种情况是因为ClearRenderTarget用命令缓冲区的名称将清除包装在sample中。我们可以在开始我们自己的sample之前通过清除来摆脱多余的嵌套。这会导致两个相邻的Render Camera示例范围,这些范围被合并。
void Setup () {
buffer.ClearRenderTarget(true, true, Color.clear); buffer.BeginSample(bufferName);//buffer.ClearRenderTarget(true, true, Color.clear);ExecuteBuffer();context.SetupCameraProperties(camera);}

清除 不嵌套
这Draw GL代表绘制一个全屏四边形Hidden/InternalClear写入渲染目标的着色器,这不是清除它的最有效方法。使用这种方法是因为我们在设置相机属性之前要进行清除。如果我们交换这两个步骤的顺序,我们就可以快速清除。
void Setup () {
context.SetupCameraProperties(camera);buffer.ClearRenderTarget(true, true, Color.clear);buffer.BeginSample(bufferName);ExecuteBuffer();//context.SetupCameraProperties(camera);}

正确清理
现在我们看到Clear (color+Z+stencil),这表明颜色和深度缓冲区都被清除。Z 代表深度缓冲区,模板数据是同一缓冲区的一部分。
我们当前看到的是天空盒,但看不到我们放置在场景中的任何对象。我们不会绘制每个对象,而是只渲染那些对相机可见的对象。为此,我们从场景中具有渲染器组件的所有对象开始,然后剔除那些落在相机视锥体之外的对象。
弄清楚可以剔除的内容需要我们跟踪多个相机设置和矩阵,为此我们可以使用该ScriptableCullingParameters结构体。我们可以在相机上调用TryGetCullingParameters,而不是自己填充它。它返回是否可以成功检索参数,因为对于退化的相机设置可能会失败。为了获取参数数据,我们必须通过out在其前面写入来将其作为输出参数提供。在返回成功或失败的单独cull方法中执行此操作。
bool Cull () {
ScriptableCullingParameters pif (camera.TryGetCullingParameters(out p)) {returntrue;}returnfalse;}
当用作输出参数时,可以将变量声明内联到参数列表中。
bool Cull () {//ScriptableCullingParameters p
if (camera.TryGetCullingParameters(outScriptableCullingParameters p)) {returntrue;}returnfalse;}
在设置Render之前插入Cull并且如果失败就丢弃掉
public void Render (ScriptableRenderContext context, Camera camera) {this.context = context;this.camera = camera;if (!Cull()) {return;}Setup();DrawVisibleGeometry();Submit();}实际的剔除是通过调用Cull上下文来完成的,上下文会生成一个CullingResults结构体。如果成功则执行此操作Cull并将结果存储在字段中。在这种情况下,我们必须通过ref在其前面写入来将剔除参数作为引用参数传递。
CullingResults cullingResults;…
bool Cull () {if (camera.TryGetCullingParameters(outScriptableCullingParameters p)) {cullingResults = context.Cull(ref p);returntrue;}returnfalse;}
一旦我们知道什么是可见的,我们就可以继续渲染这些东西。这是通过调用DrawRenderers上下文并将剔除结果作为参数来完成的,告诉它要使用哪些渲染器。除此之外,我们还必须提供绘图设置和过滤设置。两者都是结构体,DrawingSettings和FilteringSettings是我们最初将使用的默认构造函数。两者都必须通过引用传递。在绘制天空盒之前,在 DrawVisibleGeometry中执行此操作。
void DrawVisibleGeometry () {
var drawingSettings = newDrawingSettings();var filteringSettings = newFilteringSettings();context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);context.DrawSkybox(camera);}
我们还没有看到任何东西,因为我们还必须说明允许哪种类型的着色器pass。由于我们在本教程中仅支持unlit着色器,因此我们必须获取着色器标签 IDSRPDefaultUnlitpass,我们可以执行一次并将其缓存在静态字段中。
staticShaderTagId unlitShaderTagId = newShaderTagId("SRPDefaultUnlit");将其作为 DrawingSettings 构造函数的第一个参数提供,同时还需要提供一个新的 SortingSettings 结构值。将相机传递给 SortingSettings 的构造函数,因为它用于确定是使用正交排序还是基于距离的排序。
void DrawVisibleGeometry () {
var sortingSettings = newSortingSettings(camera);var drawingSettings = newDrawingSettings(unlitShaderTagId, sortingSettings);}
除此之外,我们还需要指定允许的渲染队列。将 RenderQueueRange.all 作为参数传递给 FilteringSettings 构造函数,以便我们包含所有内容。
var filteringSettings = newFilteringSettings(RenderQueueRange.all);


绘制unlit的几何图形
只有使用unlit的可见对象才会被绘制。所有的绘制调用都会在帧调试器中列出,在 RenderLoop.Draw 下进行分组。透明对象存在一些奇怪的问题,但首先让我们来看一下绘制对象的顺序。在帧调试器中,你可以通过依次选择或使用箭头键来遍历drawcall。
文章转载自
Thepoly