實現特效,尤其是一些后處理特效,經常需要將各物體的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.
- A 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組件前的對勾去掉,是一樣的效果。