unity, 替换shader渲染(Rendering with Replaced Shaders)

时间:2022-03-02 19:35:54

实现特效,尤其是一些后处理特效,经常需要将各物体的shader替换为另一套shader进行渲染到纹理,再后再进行合成或以某种叠加方式叠加到最后的画面上去。

再复杂一点儿的,可能不同的物体所用的替换shader还不一样。

unity中Camera.RenderWithShader可实现这个功能。

下面是官方文档原话:

Rendering with Replaced Shaders

Some rendering effects require rendering a scene with a different set of shaders. For example, good edge detection would need a texture with scene normals, so it could detect edges where surface orientations differ. Other effects might need a texture with scene depth, and so on. To achieve this, it is possible to render the scene with replaced shaders of all objects.

Shader replacement is done from scripting using Camera.RenderWithShader or Camera.SetReplacementShader functions. Both functions take a shader and a replacementTag.

It works like this: the camera renders the scene as it normally would. the objects still use their materials, but the actual shader that ends up being used is changed:

  • If replacementTag is empty, then all objects in the scene are rendered with the given replacement shader.
  • If replacementTag is not empty, then for each object that would be rendered:
    • The real object’s shader is queried for the tag value.
    • If it does not have that tag, object is not rendered.
    • subshader is found in the replacement shader that has a given tag with the found value. If no such subshader is found, object is not rendered.
    • Now that subshader is used to render the object.

So if all shaders would have, for example, a “RenderType” tag with values like “Opaque”, “Transparent”, “Background”, “Overlay”, you could write a replacement shader that only renders solid objects by using one subshader with RenderType=Solid tag. The other tag types would not be found in the replacement shader, so the objects would be not rendered. Or you could write several subshaders for different “RenderType” tag values. Incidentally, all built-in Unity shaders have a “RenderType” tag set.

 

其中最需要理解的是replacementTag,上面文档详细叙述了replacementTag的逻辑,为了好理解,下面换种说法重新解释一遍:

*假设脚本中调用 GetComponent<Camera>().RenderWithShader(Shader.Find("shaderX"), ""),则此摄像机本次渲染的所有物体都会使用shaderX进行渲染。

*假设脚中中调用 GetComponent<Camera>().RenderWithShader(Shader.Find("shaderX"), "myReplacementTag"),则对于本次要渲染的每个物体object(i),假设object(i)本身的shader是shader(i),如果shader(i)的所有subShader都不带"myReplacementTag"标签,则object(i)不渲染;如果shader(i)中的subShader(j)带有"myReplacementTag"标签,设此标签为"myReplacementTag"="A",则unity会去shaderX中找"myReplacementTag"="A"的subShader,如果找到了,则用shaderX的此subShader替换object(i)的原有shader;否则object(i)不渲染。

需要指出的是,"myReplacementTag"应该总是用"RenderType",原因是unity内置的所有shader都带有RenderType标签。

举两个例子:

例1,将所有的不透明物体shader替换为另一种shader进行渲染:

写一个shaderX,让其中包含一个带"RenderType"="Opaque"标签的subShader,

调用GetComponent<Camera>().RenderWithShader(Shader.Find("shaderX"), "RenderType");

例2,将所有不透明物体shader替换为一种subShader进行渲染,同时将所有透明物体shader替换为另一种shader进行渲染:

写一个shaderX,让其中包含一个带“RenderType”="Opaque"标签的subShader,再写一个带"RenderType"="Transparent"标签的subShader,

调用GetComponent<Camera>().RenderWithShader(Shader.Find("shaderX"), "RenderType");

例3,将所有“RenderType”=“myRenderType”的物体的shader替换为另一种shader进行渲染:

写一个shaderX,让其中包含一个带"RenderType"="myRenderType"标签的subShader,

调用GetComponent<Camera>().RenderWithShader(Shader.Find("shaderX"), "RenderType");

 

另外,关于Camera.RenderWithShader与Camera.SetReplacementShader的区别:

Camera.RenderWithShader只是本次渲染使用替换的shader;Camera.SetReplacementShader是自调用起以后都使用替换的shader进行渲染,直到手动调用Camera.ResetReplacementShader为止,恢复为用本身的shader进行渲染。参考;http://m.blog.csdn.net/blog/QUAN2008HAPPY/39380463

 

另外在Camera.RenderWithShader的官方文档中写道:

This is used for special effects, e.g. rendering screenspace normal buffer of the whole scene, heat vision and so on. To make use of this feature, usually you create a camera and disable it. Then call RenderWithShader on it.

也就是说,在使用RenderWithShader实现特效时通常应该将调用RenderWithShader这个函数的相机设为disable,即:GetComponent<Camera>().enabled = false,或者也可以直接在Inspector中将Camera组件前的对勾去掉,是一样的效果。