1. Preface
Recently in the Commandbuffer this piece of information, before the understanding has been more chaotic.
It's not a new thing, but I think it's a little bit more expensive than adding a camera to RT, at least by saving the depth of the sort.
This article uses two examples to explain how commandbuffer is used, but to summarize some of the official Commandbuffer cases.
2. Official case
The case address is as follows:
https://blogs.unity3d.com/cn/2015/02/06/extending-unity-5-rendering-pipeline-command-buffers/
There is a demo download link at the end of the article.
The demo contains 3 examples.
The first example, Blurryrefraction, is similar to the new camera rendering RT, rendering the screen before rendering the transparent object and blurring it. Then throw to the shader to convert to the corresponding UV space, the conversion code and grab do not repeat.
The second example deferredcustomlights, where the light container model and the third example of the decal container model, are built for space culling model, a bit similar to the raymarching, the light part of the direct access to gbuffer data to draw.
The third example, Deferreddecals, is similar to the second one, where the container model is directly a block, and the projection of the block is a bit like the three-direction projection of the terrain.
3. Study Cases
3.1-Create a standard ball in a deferred rendering environment
In general, the pit is still quite a lot of, unity of the PBR this block itself and the pipeline has interacted, so commandbuffer to light and gbuffer two stages to do the insertion.
But if it is a normal VF shader, put it in front of the screen effect to do the insertion.
This is the finish effect.
So starting from the beginning, the general idea is to draw a ball after gbuffer.
Initial code:
void OnEnable()
{
mCacheCommandBuffer = new CommandBuffer();
mCacheCommandBuffer.name = "TestCommandBuffer";
mCacheCommandBuffer.DrawRenderer(testRenderer, testMaterial, 0, -1);
Camera.main.AddCommandBuffer(CameraEvent.AfterGBuffer, mCacheCommandBuffer);
}
Release:
void OnDisable()
{
Camera.main.RemoveCommandBuffer(CameraEvent.AfterGBuffer, mCacheCommandBuffer);
mCacheCommandBuffer.Dispose();
}
Released when Dispose is to be placed after the Removecommandbuffer call.
Drawrenderer a lot more freedom than DrawMesh, but the disadvantage is that it can be tricky to encounter multidimensional sub-materials.
Here the fourth parameter is the pass that corresponds to shader, if fill 1 then all pass is drawn .
The drawing effect is as follows
(direct painting must be problematic.)
Open Framedebugger Look at the problem, the standard in all the pass is drawn out this is not desired.
Here you see the standard Pass, and the third pass is for delayed illumination, followed by pass.
And there's a problem. RT3 's spontaneous light information is incorrect.
Unity's Gbuffer in four RT are rt0-diffuse, rt1-highlight, rt2-screen Normal, rt3-spontaneous light .
Flip through the standard shader source code, found that may be missing indirect lighting information, and indirect lighting information may not be properly initialized
But I found something like this.
void fragDeferred(
VertexOutputDeferred i,
out half4 outGBuffer0 : SV_Target0,
out half4 outGBuffer1 : SV_Target1,
out half4 outGBuffer2 : SV_Target2,
out half4 outEmission : SV_Target3 // RT3: emission (rgb), --unused-- (a)
#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4)
, out half4 outShadowMask : SV_Target4 // RT4: shadowmask (rgba)
#endif
)
{
//...
}
This means that you can define the output gbuffer yourself, and you can also specify that only one gbuffer of the RT is output
void frag(
v2f i, out half4 outEmission : SV_Target3
)
{
outEmission = 0;
}
Sometimes this is very useful, because in the Commandbuffer blit a lot of channels can not copy (should be my technology not).
Draw One More time:
mCacheCommandBuffer.DrawRenderer(testRenderer, testMaterial, 0, 3);
mCacheCommandBuffer.DrawRenderer(testRenderer, testMaterial_fix, 0, -1);
Camera.main.AddCommandBuffer(CameraEvent.AfterGBuffer, mCacheCommandBuffer);
The solution is solved, but there is no light in contact with the sky box.
Check the Framedebugger, confirmed that the light part of the problem, after stepping on some pits found in the afterlighting to draw again.
void OnEnable()
{
mCacheCommandBuffer = new CommandBuffer();
mCacheCommandBuffer.name = "TestCommandBuffer";
mCacheCommandBuffer.DrawRenderer(testRenderer, testMaterial, 0, 3);
Camera.main.AddCommandBuffer(CameraEvent.AfterGBuffer, mCacheCommandBuffer);
mCacheCommandBuffer2 = new CommandBuffer();
mCacheCommandBuffer2.name = "TestCommandBuffer2";
mCacheCommandBuffer2.DrawRenderer(testRenderer, testMaterial, 0, 0);
Camera.main.AddCommandBuffer(CameraEvent.AfterLighting, mCacheCommandBuffer2);
}
3.2-Blur the Burrow model using Commandbuffer
Before others have done, think this case a bit of meaning, I tried a bit.
The complete effect is as follows
This is the finish effect, and using stencil to burrow can achieve a simulated translucent effect, but if the gradient is slower it can cause visual discomfort.
by stencil to mark the protagonist's position in the screen, and then make a Gaussian blur on the basis of the main character's burrow can alleviate this visual discomfort.
Doing stencil directly on the original model causes the stencil data to be purged during the shadow phase.
But before you change the position of Commandbuffer, switch to forward rendering to see the results of stencil not being erased.
You can see that even if the stencil comes into effect, the stencil of the burrow area has been dug out. So you have to think of another way to cover this bad stencil.
My train of thought is to draw an Alpha 0 protagonist renderer, with normal stencil, to cover the old Renderskybox after the drawrenderer.
which requires two commandbuffer.
mStencilFixCommandBuffer = new CommandBuffer();
mStencilFixCommandBuffer.name = "StencilFix"; for (int i = 0; i < playerRenderers.Length; i++)
{ var item = playerRenderers[i];
mStencilFixCommandBuffer.DrawRenderer(item, playerReplaceMaterial, 0, -1);
}
Camera.main.AddCommandBuffer(CameraEvent.AfterSkybox, mStencilFixCommandBuffer);
Camera.main.AddCommandBuffer(CameraEvent.AfterSkybox, mStencilFixCommandBuffer);
you can see that the correct stencil has been mapped (this method can also be used to modify the depth, Gbuffer)
Then there is the problem of fuzzy sampling, in which you cannot insert lambda CPU code to execute asynchronous content Commandbuffer
So here is a few RT to switch back and forth to do the repeated sampling, here refer to the official commandbuffer in the first example, need to use two RT to switch back and forth.
The new RT in Commandbuffer is recommended for this.
mBlurTempRT1 = Shader.PropertyToID("BlurTempRT1");
mBlurCommandBuffer.GetTemporaryRT(mBlurTempRT1, -1, -1, 0);
Of course, the use of this can not take the Rt object, only through the index operation.
the second and three parameters specify the resolution, 1 is the default, 2 is half the size resolution, 3 is 1/3, and so on .
Here I met the second pit,stencil information can not be copied through the channel alone, only in and Cameratarget blit operation, can read stencil information .
mBlurCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, mBlurTempRT1); for (int i = 0; i < sampleNum - 1; i++)
{
mBlurCommandBuffer.Blit(mBlurTempRT1, BuiltinRenderTextureType.CameraTarget, blurMaterial);
mBlurCommandBuffer.Blit(BuiltinRenderTextureType.CameraTarget, mBlurTempRT1);
}
mBlurCommandBuffer.Blit(mBlurTempRT1, BuiltinRenderTextureType.CameraTarget, blurMaterial);
So here's the fuzzy iteration (not quite clear here, the code can be optimized)
Finally, the effect is achieved.
Wrote here, originally wanted to do a UI panel 3D display, later found Unity PBR drawing process is a bit of egg pain.
So create a new camera. In addition these two small test not too convenient to attach source code.
Unity Commandbuffer some learning and finishing