一、SRP Batcher
简述:
- 将一组参数打包放在 GPU 上,渲染时不用切换渲染状态,从而进行渲染优化。但不能减少 DrawCall,只是降低 DrawCall 的代价
合批限制:
- Property内的属性,都要写到 CBuffer 内
- 全局变量不能写在 CBuffer 内
- CBuffer内不包含#if(非常量大小CBuffer)
- CBuffer内的变量必须按照half4 half2 half 从上到下的顺序写,顺序不能乱不能穿插的写,不然就会闪退,还有不能写half3,要用half4代替half3,不然在某些机器上会显示错误。
- 一个 Shader 里面有多个 Pass,每个 Pass 的 CBuffer 应该一致
缺点:
- SRP Bather 不支持 MaterialPropertyBlock,如果有很多个不同属性但使用相同Shader的需求,只能创建 N 多个材质,然后进行 SRP Bather
- Instance 支持 MaterialPropertyBlock,所以上面的情况,可以用 Instance + MaterialPropertyBlock 代替
二、GPU Instancing
简介:
- GPU Instancing 支持 MaterialPropertyBlock,如果有使用相同 Shader 但是不同材质属性的需求,GPU Instancing 可以进行高效处理
缺点:
- 一般来说,GPU实例化比动态批处理效果更好。这种方法也有一些注意事项,例如,当涉及到不同比例时,较大的网格的法向量不能保证是单位长度的。另外,绘制顺序也会发生变化,因为现在是单个网格而不是多个。
使用方式:
- 管线
SortingSettings sortingSettings = new SortingSettings(_camera)
{
criteria = SortingCriteria.CommonOpaque
};
DrawingSettings drawingSettings = new DrawingSettings(UnlitShaderTagId, sortingSettings)
{
enableInstancing = useGPUInstancing, //启用GPUInstancing
};
drawingSettings.SetShaderPassName(1, LitShaderTagId);
FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.opaque, renderingLayerMask: (uint) renderingLayerMask);
_context.DrawRenderers(_cullingResults, ref drawingSettings, ref filteringSettings);
- 宏定义引用文件
#pragma multi_compile_instancing
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
- 属性定义
UNITY_INSTANCING_BUFFER_START(UnityPerMaterial)
UNITY_DEFINE_INSTANCED_PROP(float4, _Color)
UNITY_DEFINE_INSTANCED_PROP(float4, _EmissionColor)
UNITY_DEFINE_INSTANCED_PROP(float4, _MainTex_ST)
UNITY_DEFINE_INSTANCED_PROP(float4, _DetailMap_ST)
UNITY_DEFINE_INSTANCED_PROP(float, _DetailAlbedo)
UNITY_DEFINE_INSTANCED_PROP(float, _DetailSmoothness)
UNITY_DEFINE_INSTANCED_PROP(float, _Cutoff)
UNITY_DEFINE_INSTANCED_PROP(float, _ZWrite)
UNITY_DEFINE_INSTANCED_PROP(float, _Metallic)
UNITY_DEFINE_INSTANCED_PROP(float, _Occlusion)
UNITY_DEFINE_INSTANCED_PROP(float, _Smoothness)
UNITY_DEFINE_INSTANCED_PROP(float, _Fresnel)
UNITY_DEFINE_INSTANCED_PROP(float, _NormalScale)
UNITY_DEFINE_INSTANCED_PROP(float, _DetailNormalScale)
UNITY_INSTANCING_BUFFER_END(UnityPerMaterial)
- 结构定义
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS_SS : SV_POSITION;
float2 uv : VAR_UV;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
- Vertex 和 Fragment 使用
Varyings LitPassVertex(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
output.positionCS_SS = TransformWorldToHClip(output.positionWS);
return output;
}
float4 LitPassFragment(Varyings input) : SV_TARGET
{
UNITY_SETUP_INSTANCE_ID(input);
float4 finalColor = UNITY_ACCESS_INSTANCED_PROP(UnityPerMaterial, _Color)
return finalColor;
}
材质球

C# 端
using UnityEngine;
using UnityEngine.Rendering;
using Random = UnityEngine.Random;
namespace CustomRP.Examples
{
public class MeshBall : MonoBehaviour
{
private static int _colorID = Shader.PropertyToID("_Color");
private static int _metallicID = Shader.PropertyToID("_Metallic");
private static int _smoothnessID = Shader.PropertyToID("_Smoothness");
[SerializeField] private Mesh mesh = default;
[SerializeField] private Material material = default;
[SerializeField] private LightProbeProxyVolume _lightProbeProxyVolume = null;
private Matrix4x4[] _matrices = new Matrix4x4[1023];
private Vector4[] _colors = new Vector4[1023];
private float[]
_metallic = new float[1023],
_smoothness = new float[1023];
private MaterialPropertyBlock _block;
private void Awake()
{
for (int i = 0; i < _matrices.Length; i++)
{
_matrices[i] = Matrix4x4.TRS(
Random.insideUnitSphere * 10f,
Quaternion.Euler(Random.value * 360f, Random.value * 360f, Random.value * 360f),
Vector3.one * Random.Range(0.5f, 1.5f));
_colors[i] = new Vector4(Random.value, Random.value, Random.value, Random.Range(0.5f, 1.5f));
_metallic[i] = Random.value < 0.25f ? 1f : 0f;
_smoothness[i] = Random.Range(0.05f, 0.95f);
}
}
private void Update()
{
if (_block == null)
{
_block = new MaterialPropertyBlock();
_block.SetVectorArray(_colorID, _colors);
_block.SetFloatArray(_metallicID, _metallic);
_block.SetFloatArray(_smoothnessID, _smoothness);
if (_lightProbeProxyVolume == null)
{
Vector3[] positions = new Vector3[1023];
for (int i = 0; i < _matrices.Length; i++)
{
positions[i] = _matrices[i].GetColumn(3);
}
SphericalHarmonicsL2[] lightProbes = new SphericalHarmonicsL2[1023];
Vector4[] occlusionProbes = new Vector4[1023];
LightProbes.CalculateInterpolatedLightAndOcclusionProbes(positions, lightProbes, occlusionProbes);
_block.CopySHCoefficientArraysFrom(lightProbes);
_block.CopyProbeOcclusionArrayFrom(occlusionProbes);
}
}
Graphics.DrawMeshInstanced(
mesh, 0, material, _matrices, 1023, _block,
ShadowCastingMode.On, true, 0, null,
_lightProbeProxyVolume ? LightProbeUsage.UseProxyVolume : LightProbeUsage.CustomProvided,
_lightProbeProxyVolume);
}
}
}
三、Dynamic Batching
简述:
- 将使用相同材质球的多个小Mesh合并成一个大Mesh,从而减小 DrawCall
缺点:
- 不支持 MaterialPropertyBlock
使用方式:
- 管线
SortingSettings sortingSettings = new SortingSettings(_camera)
{
criteria = SortingCriteria.CommonOpaque
};
DrawingSettings drawingSettings = new DrawingSettings(UnlitShaderTagId, sortingSettings)
{
enableDynamicBatching = useDynamicBatching, //启用动态批处理
};
drawingSettings.SetShaderPassName(1, LitShaderTagId);
FilteringSettings filteringSettings = new FilteringSettings(RenderQueueRange.opaque, renderingLayerMask: (uint) renderingLayerMask);
_context.DrawRenderers(_cullingResults, ref drawingSettings, ref filteringSettings);
- 禁用 SRP,他的优先级比较高
GraphicsSettings.useScriptableRenderPipelineBatching = false;
四、AlphaTest
简述:
- 是一个典型的不透明物体,也会写入深度,只是有部分像素被丢弃,队列在2450,在不透明之后半透明之前渲染。因为它丢弃了像素,所以不能保证在它后面的物体是否会渲染出来,因此为了性能优化,渲染队列在不透明之后半透明之前渲染