命令缓冲区保存渲染命令列表(“设置渲染目标,绘制网格,…”)。它们可以设置为在相机渲染(参见camera . addcommandbuffer)、灯光渲染(参见light . addcommandbuffer)或立即执行(参见Graphics.ExecuteCommandBuffer)期间的不同处执行。
通常情况下,它们会以自定义方式扩展Unity的渲染管道。例如,您可以在完成所有常规对象之后将一些附加对象渲染到延迟渲染G-buffer中,或者对光影贴图进行自定义处理。有关详细信息,请参阅 command buffers overview概述页面。
如果需要,可以创建命令缓冲区,然后多次执行。(也就是说一般使用完毕后需要手动清除缓存,如果命令是Loop的,则可以循环执行)
//
// 摘要:
// List of graphics commands to execute.
[NativeType("Runtime/Graphics/CommandBuffer/RenderingCommandBuffer.h")]
[NativeHeader("Runtime/Shaders/ComputeShader.h")]
[UsedByNativeCode]
[NativeHeader("Runtime/Shaders/RayTracingShader.h")]
[NativeHeader("Runtime/Export/Graphics/RenderingCommandBuffer.bindings.h")]
public class CommandBuffer : IDisposable
{
}
void SetViewport(Rect pixelRect);设置视口矩形大小
void EnableScissorRect(Rect scissor);设置裁剪矩形大小
void DisableScissorRect();
void DisableScissorRect();取消矩形裁剪
设置缓冲区数据
CommandBuffer.GetTemporaryRT;获取临时渲染纹理
static int nameID = Shader.PropertyToID("_FrameBuffer");
public void GetTemporaryRT(
int nameID, //这个纹理的Shader属性名。
int width, int height,
int depthBuffer, //深度缓冲位(0,16或24)。
FilterMode filter, //纹理过滤模式(默认为Point)。还有Bilinear、Trilinear
RenderTextureFormat format, //RenderTexture的格式。(常用有:ARGB32(Default)、Depth、Shadowmap、...)
RenderTextureReadWrite readWrite, //Linear,sRGB,Default(与project settings有关)
int antiAliasing, //抗锯齿(默认为no anti-aliasing)。
bool enableRandomWrite);//是否应该启用对纹理的随机写入访问(默认为false)。
使用ReleaseTemporaryRT释放临时渲染纹理,传递相同的nameID。任何没有明确释放的临时纹理将在相机完成渲染时,或在Graphics.ExecuteCommandBuffer结束后被删除。
获得临时渲染纹理后,您可以将其设置为活动(SetRenderTarget)或 blit to/from it。在命令缓冲区执行期间,您不需要显式地保留活动渲染目标(当前渲染目标将在之后保存和恢复)。
RenderTextureReadWrite:
如果使用Gamma色彩空间,RenderTextureReadWrite readWrite的设置没有任何作用。
我们可以通过RenderTexture.sRGB,了解渲染纹理使用sRGB或是Linear。如果为sRGB,返回true;如果为Linear,返回false。
释放:
void ReleaseTemporaryRT(int nameID);
public void SetRenderTarget(
Rendering.RenderTargetIdentifier color, //渲染目标设置为颜色缓冲。
Rendering.RenderBufferLoadAction colorLoadAction, //用于颜色的加载操作。
Rendering.RenderBufferStoreAction colorStoreAction, //用于颜色的存储操作。
Rendering.RenderTargetIdentifier depth, //将渲染目标设置为深度缓冲区。
Rendering.RenderBufferLoadAction depthLoadAction, //用于深度/模板缓冲区的加载操作。
Rendering.RenderBufferStoreAction depthStoreAction);//用于深度/模板缓冲区的存储操作
public void SetRenderTarget(
RenderTargetIdentifier[] colors, // MRT 多重纹理渲染(DBuffer)
Rendering.RenderTargetIdentifier depth,
int mipLevel, //要渲染到的渲染目标的mip级别。
CubemapFace cubemapFace, //要渲染到立方体哪一个方向的表面。
int depthSlice); //要设置的3D或阵列渲染目标的层。
渲染纹理可以用几种方式表示:一个RenderTexture对象,一个用GetTemporaryRT创建的临时渲染纹理,或者一个内置的临时纹理(BuiltinRenderTextureType)。所有这些都由RenderTargetIdentifier结构体表示,该结构体具有隐式转换操作符以节省输入。
Rendering.RenderBufferLoadAction
当GPU开始渲染到渲染目标时,此设置指定应该在表面的现有内容上执行的操作。如果加载动作是Clear或not care,Tile-based GPUs可能会获得性能优势。用户应该避免使用RenderBufferLoadAction。尽可能Load 。
请注意,并非所有平台都有加载/存储操作,因此此设置可能在运行时被忽略。通常面向移动设备的图形api (OpenGL ES, Metal)会利用这些设置。
如果你使用RenderBufferLoadAction.DontCare,渲染可能会失败或产生伪影,因为深度纹理中未定义的像素会导致深度测试失败。你可以使用LoadStoreActionDebugModeSettings 来突出显示未定义的像素。
Rendering.RenderBufferStoreAction
这个枚举描述了当GPU完成渲染到渲染目标时应该在渲染目标上做什么。
当GPU完成渲染到渲染目标时,此设置指定应该对渲染结果执行的操作。如果存储操作为“不关心”,基于tile的gpu可能会获得性能优势。例如,如果渲染帧后不需要深度缓冲区内容,则此设置可能很有用。
请注意,并非所有平台都有加载/存储操作,因此此设置可能在运行时被忽略。通常面向移动设备的图形api (OpenGL ES, Metal)会利用这些设置。
如果你使用RenderBufferLoadAction.DontCare,渲染可能会失败或产生伪影,因为深度纹理中未定义的像素会导致深度测试失败。你可以使用LoadStoreActionDebugModeSettings来突出显示未定义的像素。
void Blit(Texture source, Rendering.RenderTargetIdentifier dest, Material mat, int pass);
添加一个命令,使用着色器将纹理中的像素数据复制到渲染纹理中。
这个方法增加了一个命令,将像素数据从GPU上的纹理复制到GPU上的渲染纹理。这是复制纹理最快的方法之一。
当你使用Graphics.Blit, Unity做了以下几点:
如果你提供一个没有_MainTex属性的mat材质,Blit不会使用source。
你可以使用Graphics.Blit创建后处理效果,通过设置 自定义着色器 mat 到一个材质。
Blit改变了RenderTexture.active。在使用Blit之前存储active render texture,如果之后需要使用它。
避免将source和dest设置为相同的渲染纹理,因为这可能导致未定义的行为。使用带有双缓冲的自定义渲染纹理代替,或者使用两个渲染纹理并在它们之间交替手动实现双缓冲。
在线性色彩空间中,在使用Blit之前设置GL.sRGBWrite,以确保srgb到线性色彩转换是您所期望的。
要在内置渲染管道中blit到屏幕上,请遵循以下步骤:
要在通用渲染管道(URP)或高清晰度渲染管道(HDRP)中将数据blit到屏幕上,必须在你从RenderPipelineManager.endContextRendering调用的方法中回调处调用Graphics.Blit或 CommandBuffer.Blit。
如果你想使用源(渲染)纹理一部分的深度或模板缓冲区,或者blit到纹理的子区域,你必须手动编写一个等效的Graphics.Blit函数——即,使用目标颜色缓冲区和源深度缓冲区设置Graphics.SetRenderTarget ,设置orthographic projection(GL.LoadOrtho),设置材质通道(material .setpass)并绘制一个四边形(GL.Begin)。
通常不需要保存Blit dest的先前内容。在这种情况下,建议使用SetRenderTarget使用适当的加载和存储操作显式地激活dest渲染目标。Blit dest应该被设置为BuiltinRenderTextureType.CurrentActive。
Shader关键字设置
//添加一个命令来禁用全局或本地着色器关键字。
void DisableKeyword(ref Rendering.GlobalKeyword keyword);
void DisableKeyword(ComputeShader computeShader, ref Rendering.LocalKeyword keyword);
void DisableKeyword(Material material, ref Rendering.LocalKeyword keyword);
//添加一个命令来禁用一个给定名称的全局shader关键字。
void DisableShaderKeyword(string keyword);
void EnableKeyword(ref Rendering.GlobalKeyword keyword);
.....
设置全局变量
void SetGlobalFloat(string name, float value);
void SetGlobalFloat(int nameID, float value);
同理还有FLoatArray、Int、Matrix、MatrixArray、Texture、Vector、VectorArray
void SetProjectionMatrix(Matrix4x4 proj);
void SetViewMatrix(Matrix4x4 view);
void SetViewProjectionMatrices(Matrix4x4 view, Matrix4x4 proj);
渲染纹理绑定:绑定渲染纹理后,才能再Pass中使用该Texture。当命令缓冲区将被执行时,一个全局着色器纹理属性将在此时被设置。
public void SetGlobalTexture(string name, Rendering.RenderTargetIdentifier value);
public void SetGlobalTexture(int nameID, Rendering.RenderTargetIdentifier value);
public void SetGlobalTexture(string name, Rendering.RenderTargetIdentifier value, Rendering.RenderTextureSubElement element);
public void SetGlobalTexture(int nameID, Rendering.RenderTargetIdentifier value, Rendering.RenderTextureSubElement element);
所有的绘制命令都不会自动添加关于光照、阴影、全局光照等相关数据,如果需要相关变量数据,需要手动设置参数数据。否则,如果在Shader中使用相关变量,结果是未定义的。
// 一般绘制
void DrawMesh(Mesh mesh, Matrix4x4 matrix, Material material, int submeshIndex = 0, int shaderPass = -1, MaterialPropertyBlock properties = null);
// 实例化绘制
void DrawMeshInstanced(Mesh mesh, int submeshIndex, Material material, int shaderPass, Matrix4x4[] matrices, int count, MaterialPropertyBlock properties);
void DrawMeshInstanced(Mesh mesh, int submeshIndex, Material material, int shaderPass, Matrix4x4[] matrices, int count);
void DrawMeshInstanced(Mesh mesh, int submeshIndex, Material material, int shaderPass, Matrix4x4[] matrices);
// renderer数据绘制
void DrawRenderer(Renderer renderer, Material material, int submeshIndex = 0, int shaderPass = -1);
//程序化绘制
public void DrawProcedural(
Matrix4x4 matrix, //使用的转化矩阵Matrix4x4.identity
Material material, //哪一个Shader
int shaderPass, //哪一个Pass
MeshTopology topology, //程序几何的拓扑结构。MeshTopology.Triangles
int vertexCount, //要渲染的索引计数。
int instanceCount = 1, //要渲染的实例数。
MaterialPropertyBlock properties = null);//在渲染之前应用额外的材料属性。
void DrawMeshInstancedProcedural(Mesh mesh, int submeshIndex, Material material, int shaderPass, int count, MaterialPropertyBlock properties);
// 不常用绘制
void DrawMeshInstancedIndirect(Mesh mesh, int submeshIndex, Material material, int shaderPass, ComputeBuffer bufferWithArgs, int argsOffset, MaterialPropertyBlock properties);
void DrawProceduralIndirect(Matrix4x4 matrix, Material material, int shaderPass, MeshTopology topology, ComputeBuffer bufferWithArgs, int argsOffset, MaterialPropertyBlock properties);
void DrawOcclusionMesh(RectInt normalizedCamViewport);
程序化绘制Procedural(没有任何顶点或索引缓冲区)
当命令缓冲区执行时,这将在GPU上执行绘制调用,没有任何顶点或索引缓冲区。这主要用于Shader Model 4.5级硬件,Shader可以从ComputeBuffer缓冲区读取任意数据。
在顶点着色器中,你通常会使用SV_VertexID和SV_InstanceID输入变量从而从一些缓冲区中获取数据。
注意,这个drawCall不会设置任何与照明相关的着色器数据(光的颜色,方向,阴影,光和反射探针等)。如果材质使用的着色器使用任何与照明相关的变量,结果是未定义的。
将源纹理转换并复制到具有不同格式或尺寸的目标纹理
// 参数:
// src:原纹理
// dst:目标纹理.
// srcElement:纹理下标(例如CubeMap,Texture2DArray等)
// dstElement:目标纹理下标
// Destination element (e.g. cubemap face or texture array element).
public void ConvertTexture(RenderTargetIdentifier src, RenderTargetIdentifier dst)
public void ConvertTexture(RenderTargetIdentifier src, int srcElement, RenderTargetIdentifier dst, int dstElement)
// 只用于GraphicsBuffer 的复制(VAO数据)
CopyBuffer(GraphicsBuffer source, GraphicsBuffer dest);
// 用于 ComputeBuffer GraphicsBuffer 的复制
CopyCounterValue(ComputeBuffer/GraphicsBuffer src, ComputeBuffer/GraphicsBuffer dst, uint dstOffsetBytes);
//格式必须相同
CopyTexture(Rendering.RenderTargetIdentifier src, Rendering.RenderTargetIdentifier dst);
纹理计数器
void IncrementUpdateCount(Rendering.RenderTargetIdentifier dest);
背面剔除反转
CommandBuffer.SetInvertCulling
该标志可“翻转”所有已渲染对象的剔除模式。主要用例:渲染镜子、水等的反射。由于为用于渲染此反射的虚拟摄像机生成了镜像,因此必须反转剔除顺序。您可以看到 Effects 标准包中的 Water 脚本是怎样编写的。
异步
//回调
void RequestAsyncReadback
void RequestAsyncReadbackIntoNativeArray<T>
void RequestAsyncReadbackIntoNativeSlice<T>
void WaitAllAsyncReadbackRequests();
//同步处理,GPU在完成Blit, Clear, Draw, Dispatch或纹理复制命令后通过GraphicsFence
Rendering.GraphicsFence CreateAsyncGraphicsFence(Rendering.SynchronisationStage stage);
void WaitOnAsyncGraphicsFence(Rendering.GraphicsFence fence);
void WaitOnAsyncGraphicsFence(Rendering.GraphicsFence fence, Rendering.SynchronisationStage stage);
// 异步执行Flag
void SetExecutionFlags(Rendering.CommandBufferExecutionFlags flags);
本地插件
IssuePluginCustomBlit
IssuePluginCustomTextureUpdateV2
IssuePluginEvent
IssuePluginEventAndData
IssuePluginEventAndDataWithFlags
ComputeShader
添加一个命令来设置ComputeShader上的参数。
添加一个命令来执行ComputeShader。
void DispatchCompute(ComputeShader computeShader, int kernelIndex, int threadGroupsX, int threadGroupsY, int threadGroupsZ);
void DispatchCompute(ComputeShader computeShader, int kernelIndex, ComputeBuffer indirectBuffer, uint argsOffset);
void DispatchCompute(ComputeShader computeShader, int kernelIndex, GraphicsBuffer indirectBuffer, uint argsOffset);
RayTracing
添加了一个命令来选择在执行光线/几何相交时使用哪个着色器通道着色。
SetRayTracingShaderPass
添加一个命令来执行RayTracingShader。
void DispatchRays(
Experimental.Rendering.RayTracingShader rayTracingShader,
string rayGenName,
uint width, uint height, uint depth,
Camera camera);
SetRayTracingAccelerationStructure
SetRayTracingBufferParam
SetRayTracingConstantBufferParam
SetRayTracingFloatParam
SetRayTracingIntParam
SetRayTracingMatrixParam
SetRayTracingTextureParam
SetRayTracingVectorParam
XR
void SetFoveatedRenderingMode(Rendering.FoveatedRenderingMode foveatedRenderingMode);
SetInstanceMultiplier
其他
SetShadowSamplingMode
CommandBuffer.SetSinglePassStereo(SinglePassStereoMode)
// 延迟锁定
void UnmarkLateLatchMatrix(Rendering.CameraLateLatchMatrixType matrixPropertyType);
定义自定义 RenderPipeline 时,可使用 ScriptableRenderContext 向 GPU 调度和提交状态更新和绘制命令。
RenderPipeline.Render 方法实现通常会针对每个摄像机剔除渲染管线不需要渲染的对象(请参阅 CullingResults),然后对 ScriptableRenderContext.DrawRenderers 发起一系列调用并混合 ScriptableRenderContext.ExecuteCommandBuffer 调用。这些调用会设置全局着色器属性、更改渲染目标、分发计算着色器和其他渲染任务。 若要实际执行渲染循环,请调用 ScriptableRenderContext.Submit。
public Rendering.CullingResults Cull (ref Rendering.ScriptableCullingParameters parameters);
基于通常从当前渲染的摄像机获取的 ScriptableCullingParameters 来执行剔除。
剔除结果绑定到将与之结合使用的 ScriptableRenderContext;剔除结果所用的内存会在渲染循环完成后得到释放。
void DrawGizmos (Camera camera, Rendering.GizmoSubset gizmoSubset);
...//BeforeRendering
...//不透明物体渲染
...//透明物体渲染
if (drawGizmos)
{
DrawGizmos(context, camera, GizmoSubset.PreImageEffects);
}
...//AfterRendering
if (drawGizmos)
{
DrawGizmos(context, camera, GizmoSubset.PostImageEffects);
}
void DrawRenderers (
Rendering.CullingResults cullingResults, //从ScriptableRenderContext.Cull中获得
ref Rendering.DrawingSettings drawingSettings, //DrawRenderers的设置。
// 包含:enableDynamicBatching 是否开启动态批处理
// enableInstancing 是否开启实例化
// fallbackMaterial 材质失败的备用材质
// mainLightIndex 配置什么灯应该被用作主灯。
// overrideMaterial 设置要在该组中渲染的所有物体使用的材质。
// overrideMaterialPassIndex Pass下标
/* perObjectData LightProbe/
ReflectionProbes/
LightProbeProxyVolume/
Lightmaps/
LightData/
MotionVectors/
LightIndices/
ReflectionProbeData/
OcclusionProbe/
OcclusionProbeProxyVolume/
shadowMask*/
// sortingSettings 渲染排序顺序
ref Rendering.FilteringSettings filteringSettings, //过滤渲染的物体(层级,QueueRange等)
ref Rendering.RenderStateBlock stateBlock);//
RenderStateBlock结构:
//SetDetphState
m_RenderStateBlock.mask |= RenderStateMask.Depth;
m_RenderStateBlock.depthState = new DepthState(writeEnabled, function);
//SetStencilState
m_RenderStateBlock.mask |= RenderStateMask.Stencil;
m_RenderStateBlock.stencilReference = reference;
m_RenderStateBlock.stencilState = stencilState;
在各种Pass中使用,例如:
```cpp
class RenderObjectsPass : ScriptableRenderPass
{
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
....
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
// Render the objects...
context.DrawRenderers(
renderingData.cullResults,
ref drawingSettings,
ref m_FilteringSettings,
ref m_RenderStateBlock);
}
}
//Rendering.ShadowDrawingSettings settings 在此处定义
var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex);
for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex)
{
// 此处设置级联阴影数据
settings.splitData = m_CascadeSlices[cascadeIndex].splitData;
Vector4 shadowBias = ShadowUtils.GetShadowBias(
ref shadowLight,
shadowLightIndex,
ref shadowData,
m_CascadeSlices[cascadeIndex].projectionMatrix,
m_CascadeSlices[cascadeIndex].resolution);
ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias);
CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false);
ShadowUtils.RenderShadowSlice(cmd,
ref context,
ref m_CascadeSlices[cascadeIndex],
ref settings,
m_CascadeSlices[cascadeIndex].projectionMatrix,
m_CascadeSlices[cascadeIndex].viewMatrix);
}
//在RenderShadowSlice函数中使用了DrawShadows
public static void RenderShadowSlice(CommandBuffer cmd, ref ScriptableRenderContext context,
ref ShadowSliceData shadowSliceData, ref ShadowDrawingSettings settings,
Matrix4x4 proj, Matrix4x4 view)
{
cmd.SetGlobalDepthBias(1.0f, 2.5f); // these values match HDRP defaults (see https://github.com/Unity-Technologies/Graphics/blob/9544b8ed2f98c62803d285096c91b44e9d8cbc47/com.unity.render-pipelines.high-definition/Runtime/Lighting/Shadow/HDShadowAtlas.cs#L197 )
cmd.SetViewport(new Rect(shadowSliceData.offsetX, shadowSliceData.offsetY, shadowSliceData.resolution, shadowSliceData.resolution));
cmd.SetViewProjectionMatrices(view, proj);
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
context.DrawShadows(ref settings);
cmd.DisableScissorRect();
context.ExecuteCommandBuffer(cmd);
cmd.Clear();
cmd.SetGlobalDepthBias(0.0f, 0.0f); // Restore previous depth bias values
}
DrawSkybox函数在DrawSkyboxPass使用,作为单独的一个Pass。
为给定的场景视图相机安排线框覆盖的绘制。
注意,DrawWireOverlay只在Unity编辑器中起作用,
而且需要 Camera.cameraType
设置为 CameraType.SceneView
,
并且SceneView.CamerMode.drawMode
设置为 DrawCameraMode.TexturedWire
。
如果不满足这些条件,调用DrawWireOverlay就没有效果。
提交CommandBuffer缓存,提交后需要手动清除。
ExecuteCommandBufferAsync(Rendering.CommandBuffer commandBuffer, Rendering.ComputeQueueType queueType);
,是对异步计算队列调度命令缓冲区的执行。另请参阅:SystemInfo.supportsAsyncCompute、GPUFence。
此函数可用于设置视图、投影和裁剪面全局着色器变量。
将所有调度命令都提交给渲染循环来执行。
Submit与ExecuteCommandBuffer的区别:
在调用ScriptableRenderContext.ExecuteCommandBuffer
期间, ScriptableRenderContext将commandBuffer参数注册到其要执行的命令的内部列表中。这些命令(包括存储在自定义commandBuffer中的命令)的实际执行发生在ScriptableRenderContext.Submit期间。
如果您的绘制调用依赖于您在CommandBuffer中指定的管道状态,请确保在其他ScriptableRenderContext方法(如DrawRenderers, DrawShadows)之前调用ExecuteCommandBuffer。
即:如果DrawRenderers需要CommandBuffer中的命令作为前置条件,则必须先提交缓存命令,再使用DrawRenderers函数。否则,即使在DrawRenderers函数之前将命令添加到了commandBuffer,但会因为提交顺序导致最终结果的不正确。
此方法提交了所有的预设命令到rendering loop用于检查。这个验证检查 由BeginRenderPass调用启动的渲染传递是否可以执行预定的命令。
context.InvokeOnRenderObjectCallback();
在InvokeOnRenderObjectCallbackPass.cs中调用context.InvokeOnRenderObjectCallback();
作为MonoBehaviour 脚本调度 OnRenderObject 回调的调用。
ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
将 UI 几何形状发射到 Scene 视图以进行渲染。
#if UNITY_EDITOR
// Emit scene view UI
if (isSceneViewCamera)
{
ScriptableRenderContext.EmitWorldGeometryForSceneView(camera);
}
#endif