趣投稿|走进 Stencil Buffer 系列 4:Stencil 后处理局部描边( 二 )


趣投稿|走进 Stencil Buffer 系列 4:Stencil 后处理局部描边
本文插图

bunny 材质 Shader 中写入 Stencil 参考值 2 , cube 不写入参考值
然后创建后处理StencilOutlinePostProcessing.cs脚本 。
在脚本里我们声明两个材质 , 一个用于后处理提取 Stencil并转换为图像的材质StencilProcessMat , 一个用于后处理边缘检测的描边材质OutlinePostProcessByStencilMat;
还有两个渲染纹理 , 一个用于承接屏幕渲染结果图像的cameraRenderTexture , 一个用于承接颜色图像形式StencilBuffer的stencilBufferToColor 。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StencilOutlinePostProcessing : MonoBehaviour
{
//用于后处理描边的材质public Material OutlinePostProcessByStencilMat;//用于提取出纯颜色形式的 StencilBuffer 的材质public Material StencilProcessMat;//屏幕图像的渲染纹理private RenderTexture cameraRenderTexture;//纯颜色形式的 StencilBufferprivate RenderTexture stencilBufferToColor;private Camera mainCamera;
}
然后 , 就是初始化部分 , 两个渲染纹理都设置为一个深度缓冲区中的位数是 24 位的渲染纹理 , (可选 0 , 16 , 24;但只有 24 位具有模板缓冲区) , 是因为 24 位缓冲区里包括了 16 为的深度缓冲 depthBuffer , 和 8 位的模板缓冲stencilBuffer 。 并且对用于边缘检测的OutlinePostProcessByStencilMat材质传入了stencilBufferToColor即后面用来承载颜色图像形式的StencilBuffer渲染纹理 。
void Start
{
mainCamera = GameObject.FindWithTag(''MainCamera'').GetComponent;//创建一个深度缓冲区中的位数是 24 位的渲染纹理 , (可选 0 , 16 , 24;但只有 24 位具有模板缓冲区)cameraRenderTexture = new RenderTexture(Screen.width,Screen.height,24);//因为无法直接获得 Stencil Buffer , //将 renderTexture 中的被 Stencil 标记的像素转换成一张纯颜色的渲染纹理stencilBufferToColor = new RenderTexture(Screen.width,Screen.height,24);OutlinePostProcessByStencilMat.SetTexture(''_StencilBufferToColor'',stencilBufferToColor);
}
然后脚本的后处理部分 。 这里要特别注意一下 , 通常情况后处理下都是在 void OnRenderImage(RenderTexture src, RenderTexture dest) 函数 内操作的 , 不过经过实验和资料查询 [5] , 在调用 OnRenderImage之前 , 就已经把src中的 Stencil buffer 清除掉了 。 这真是一个致命伤啊...那我们该怎么办呢?
我们来看看 Unity 生命周期的 Scene rendering 渲染阶段 [6]
趣投稿|走进 Stencil Buffer 系列 4:Stencil 后处理局部描边
本文插图
在OnRenderImage函数前还有OnPostRender函数 , 那我们的逻辑可以放到OnPostRender函数里 , 从而实现屏幕后处理效果 。 还要注意一点的是OnPostRender函数是没有参数的 , 即意味着我们要自己去获得屏幕图像 。 而OnPreRender函数在照相机开始渲染场景之前调用,我们可以在OnPreRender中就设置摄像机渲染的屏幕图像目标是我们设定创建的cameraRenderTexture 。
好的 , 接下来就是我们的后处理部分代码 。
void OnPreRender
{
//将摄像机的渲染结果传到 cameraRenderTexture 中mainCamera.targetTexture = cameraRenderTexture;
}
void OnPostRender
{
// 意味着 camera 渲染结果直接交付给 FramBuffermainCamera.targetTexture = ;//设置 Graphics 的渲染操作目标为 stencilBufferToColor//即 Graphics 的 activeColorBuffer 和 activeDepthBuffer 都是 stencilBufferToColor 里的Graphics.SetRenderTarget(stencilBufferToColor);//清除 stencilBufferToColor 里的颜色和深度缓冲区内容 , 并设置默认颜色为(0 , 0 , 0 , 0)GL.Clear(true,true,new Color(0,0,0,0));//设置 Graphics 的渲染操作目标//即 Graphics 的 activeColorBuffer 是 stencilBufferToColor 的 ColorBuffer//Graphics 的 activeDepthBuffer 是 cameraRenderTexture 的 depthBufferGraphics.SetRenderTarget(stencilBufferToColor.colorBuffer,cameraRenderTexture.depthBuffer);//提取出纯颜色形式的 StencilBuffer://将 cameraRenderTexture 通过 StencilProcessMat 材质提取出到 Graphics.activeColorBuffer//即提取到 stencilBufferToColor 中Graphics.Blit(cameraRenderTexture,StencilProcessMat);//将 cameraRenderTexture 通过 OutlinePostProcessMat 材质//并与材质中的 _StencilBufferToColor 进行边缘检测操作//最后输出到 FrameBuffer( 意味着直接交付给 FramBuffer)Graphics.Blit(cameraRenderTexture, as RenderTexture,OutlinePostProcessByStencilMat);


推荐阅读