听美术同学多次说起 Unity3D 的 Command Buffers,花10分钟学了下,写个 blog,备忘。:-)
- 将 3D Draw API 的内容,封装到 C# 层面
- 在 rendering pipeline 的某个阶段,将 command buffer 插入进去,用于生成某些需要的贴图,也称为 RT(rendering target)
- 位于 Unity.Rendering.CommandBuffer
- 以 Introduction To CommandBuffer 为例,解读之
- (1) 毛玻璃效果的面片,挂接了 (2) 和 (3)
- (2) MonoBehaviour (.cs 文件)
- (3) shader 文件
Tick & Rendering
- (2) 先运行,处于引擎的 Tick 阶段
- (3) 后运行,处于引擎的 Rendering 阶段
- new CommandBuffer(), 一堆 3D API 指令集合
- blurredGrabTex = Shader.PropertyToID("_BlurredGrabTex"); 和 shader 那边关联起来
- Camera.main.AddCommandBuffer(),在渲染的某个阶段,插入这段 buffer 指令(3D API 指令集合)
- buffer.GetTemporaryRT(), 创建 temporary render target
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
namespace FI
{
public class BlurredDistortion : MonoBehaviour
{
[SerializeField, Range(0, 3)]
private int iterations;
private CommandBuffer buffer;
private Material gaussianBlurMaterial;
private int temporaryTex;
private int blurredGrabTex;
// -------------------------------------
private void Start()
{
CreateBuffer();
InitializePropertiesAndMaterials();
}
// ------------------
private void Update()
{
UpdateBuffer();
}
// ----------------------------------------------------------
private void InitializePropertiesAndMaterials()
{
temporaryTex = Shader.PropertyToID("_TempGrabTex");
blurredGrabTex = Shader.PropertyToID("_BlurredGrabTex");
gaussianBlurMaterial =
new Material(Shader.Find("FI/GaussianBlur"));
}
// ---------------------------------------------------------------
private void CreateBuffer()
{
buffer = new CommandBuffer();
buffer.name = "BlurredGrabTexture";
Camera.main.AddCommandBuffer(CameraEvent.AfterSkybox, buffer);
}
// --------------------------------------------------------------------------
private void UpdateBuffer()
{
buffer.Clear();
buffer.GetTemporaryRT(blurredGrabTex,
-2, -2, 0, FilterMode.Bilinear);
buffer.GetTemporaryRT(temporaryTex,
-2, -2, 0, FilterMode.Bilinear);
buffer.Blit(BuiltinRenderTextureType.CurrentActive, blurredGrabTex);
for (int i = 0; i < iterations; i++)
{
buffer.Blit(blurredGrabTex, temporaryTex, gaussianBlurMaterial, 0);
buffer.Blit(temporaryTex, blurredGrabTex, gaussianBlurMaterial, 1);
}
}
}
}
- sampler2D _BlurredGrabTex,采样的贴图,由 .cs文件 中的 "Command Buffers 代码" 生成
- 相当于 diffuse map 从 .cs 中生成
Shader "FI/BlurredDistortion"
{
Properties
{
_Distortion("Distortion", Range(0, 16)) = 8
_NormalMap("NormalMap", 2D) = "bump" {}
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float2 uv : TEXCOORD0;
float4 uvgrab : TEXCOORD1;
float4 vertex : SV_POSITION;
};
sampler2D _NormalMap, _BlurredGrabTex;
float4 _NormalMap_ST, _BlurredGrabTex_TexelSize;
float _Distortion;
v2f vert (appdata_base v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.texcoord, _NormalMap);
o.uvgrab = ComputeGrabScreenPos(o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float2 bump = UnpackNormal(tex2D(_NormalMap, i.uv)).rg;
float2 offset = _Distortion * bump * _BlurredGrabTex_TexelSize.xy;
#if defined(UNITY_Z_0_FAR_FROM_CLIPSPACE)
i.uvgrab.xy = offset * UNITY_Z_0_FAR_FROM_CLIPSPACE(i.uvgrab.z) + i.uvgrab.xy;
#else
i.uvgrab.xy = offset * i.uvgrab.z + i.uvgrab.xy;
#endif
fixed4 col = tex2Dproj(_BlurredGrabTex, UNITY_PROJ_COORD(i.uvgrab));
return col;
}
ENDCG
}
}
}
- 官方介绍:Graphics Command Buffers
- API 参考:Unity.Rendering.CommandBuffer
- move哥的文章:Command Buffers in Unity