目录
目的:理解RenderType的作用 ,当初学习《Shader入门精要》时写有如下总结
一、 Camera.SetReplacementShader实战
二、Camera.SetReplacementShader总结
目的:理解RenderType的作用 ,当初学习《Shader入门精要》时写有如下总结
https://blog.csdn.net/qq_39574690/article/details/98440963
使用替换的着色器渲染(官方解释)
一些渲染效果需要使用一组不同的着色器渲染场景。例如,良好的边缘检测将需要具有场景法线的纹理,因此它可以检测表面方向不同的边缘。其他效果可能需要具有场景深度的纹理,依此类推。为此,可以使用替换后的所有对象着色器渲染场景。
可以通过使用Camera.RenderWithShader或Camera.SetReplacementShader函数编写脚本来完成着色器替换。这两个函数都带有一个着色器和一个replaceTag。
它的工作方式是这样的:相机照常渲染场景。这些对象仍然使用其材质,但是最终使用的实际着色器已更改:
- 如果replaceTag为空,则使用给定的替换着色器渲染场景中的所有对象。
- 如果replacementTag不为空,则对于将要呈现的每个对象:
因此,如果所有着色器都具有一个“ RenderType”标签,其值如“ Opaque”,“ Transparent”,“ Background”,“ Overlay”,则可以编写一个替换着色器,该着色器仅通过使用一个子着色器来渲染实体对象。 RenderType = Solid 标签。在替换着色器中找不到其他标记类型,因此将不渲染对象。或者,您可以为不同的“ RenderType”标签值编写多个子着色器。附带地,所有内置的Unity着色器都有一个“ RenderType”标签集。
一、 Camera.SetReplacementShader实战
1、准备三个Shader和对应的材质,Shader如下
Shader "Custom/SimpleSurface"
{
SubShader{
Tags
{
"RenderType"="Opaque"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = 1;
}
ENDCG
}
Fallback "Diffuse"
}
Shader "Custom/SimpleSurfaceTest2"
{
SubShader{
Tags
{
"RenderType"="Transparent"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = fixed4(1,0,0,1);
}
ENDCG
}
Fallback "Diffuse"
}
Shader "Custom/SimpleSurfaceTest3"
{
SubShader{
Tags
{
"RenderType"="NoRender"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = fixed4(0,0,1,1);
}
ENDCG
}
Fallback "Diffuse"
}
2、在场景上创建三个球体,并分别赋予上面3个Shader对应的材质球,效果图如下
3、编写一个C#脚本,挂载于摄像机上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraReplaceShader : MonoBehaviour
{
public Shader shader; //替换Shader
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Camera.main.SetReplacementShader(shader, "RenderType");
}
if (Input.GetKeyDown(KeyCode.Escape))
{
Camera.main.ResetReplacementShader();//恢复
}
}
}
4、编写一个替换Shader,如下
Shader "Custom/SimpleSurfaceReplace"
{
SubShader{
Tags
{
"RenderType" = "Opaque" //将摄像机照射到Shader(其RenderType为Opaque)替换
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = 0.2; //深灰色
}
ENDCG
}
SubShader{
Tags
{
"RenderType" = "Transparent" //将摄像机照射到的Shader(其RenderType为Transparent)替换
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = fixed4(1,1,0,1); //黄色
}
ENDCG
}
//因为没有为其他RenderType进行编写SubShader块,所以摄像机照射到的Shader其RenderType即不是Opaque也不是Transparent的
//这些Shader就不会渲染了,在此实战中RenderType为NoRender不会被渲染(蓝色球不会渲染)
Fallback "Diffuse"
}
5、将替换Shader赋值到3创建的摄像机脚本上
6、运行游戏,一开始会看到正常的颜色,按空格后会使用替换Shader进行替换相应的Shader,替换前后效果分别如下。
可见,白色球RenderType为Opaque 被替换成深灰色,红色球RenderType为Transparent 被替换成黄色,蓝色球RenderType为NoRender没有被渲染(因为替换Shader并没有针对NoRender编写SubShader代码块)
注意:Scene场景上依然是正常的渲染情况,原理未知可能是Game窗口才会处理(类似屏幕后处理?)
二、Camera.SetReplacementShader总结
Camera.SetReplacementShader(Shader, string);
参数1:替换Shader,参数2:标签名称 (SubShader块的Tags标签,一共有7个)
Queue, RenderType, DisableBatching, ForceNoShadowCasting, IgnoreProjector, CanUseSpriteAtlas, PreviewType
为什么使用RenderType是因为RenderType标签本身在Shader块中无意义,它的意义就是为了让这个摄像机替换Shader方法识别的。
当参数2为""时,使用替换Shader替换摄像机照射到的所有Shader,从替换Shader找出第一个可用的SubShader进行渲染,测试结果如下,(想想为什么替换后全部变成深灰色了)
当参数2为"RenderType"时,进行如上说明的替换,流程如下:
① 获取摄像机照射到的物体Shader的RenderType对应的字符串值,比如:Opaque。
② 从替换Shader(参数1设置的Shader)中找到RenderType为①步骤获取到的RenderType字符串值
若能找到,则使用该RenderType所在的SubShader来进行渲染步骤①中所说的物体;
若没找到,则不渲染步骤①中所说的物体。
三、Camera.RenderWithShader实战
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraReplaceShader : MonoBehaviour
{
public Shader shader; //替换Shader
public Shader shader2;
private new Camera camera;
private void Start()
{
camera = GetComponent<Camera>();
}
bool isOn;
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
camera.SetReplacementShader(shader, "");
}
if (Input.GetKeyDown(KeyCode.Escape))
{
camera.ResetReplacementShader();//恢复
isOn = false;
camera.enabled = true;
}
if (Input.GetKeyDown(KeyCode.C))
{
isOn = true;
camera.enabled = false;
}
if (isOn)
{
camera.RenderWithShader(shader2, "");//使用shader2来渲染camera摄像机照射到的物体
camera.RenderWithShader(shader2, "RenderType");//同样与SetReplacementShader一样,可指定第二个参数为RenderType
//区别在于它不会直接把这个摄像机替换后渲染的效果显示出来,而是保存在摄像机的目标纹理中camera.targetTexture
//可以设置一个RenderTexture到摄像机targetTexuture属性上观察其替换后的渲染效果
}
}
}
Shader "Custom/SimpleSurfaceAllReplace"
{
//替换Opaque的Shader
SubShader{
Tags
{
"RenderType"="Opaque"
}
CGPROGRAM
#pragma surface surf Lambert
struct Input {
float4 color : COLOR;
};
void surf(Input IN, inout SurfaceOutput o) {
o.Albedo = fixed4(0.6,0.3,1,1);//紫色
}
ENDCG
}
Fallback "Diffuse"
}
摄像机目标纹理如下所示,只有RenderType=Opaque 的Shader被替换成功,其他都没有渲染(因为没编写对应的SubShader)
注意:这里要新创建一个摄像机并禁用摄像机组件,因为这种替换方法只会把结果存储到目标纹理中。
四、Camera.RenderWithShader总结
Camera.RenderWithShader(Shader, string);
参数1:替换Shader 参数2:标签
参数含义和Camera.SetReplacementShader方法一样,不同的是这个方法会把摄像机渲染的图片存储在摄像机目标纹理Target Texture中,而Camera.SetReplacementShader方法会直接输出到颜色缓冲区。
该方法常用于屏幕后处理操作中,比如我写的针对指定物体进行描边处理就有使用到。https://blog.csdn.net/qq_39574690/article/details/102880275