【Shader进阶】SubShader块标签Tags——RenderType

目录

目的:理解RenderType的作用 ,当初学习《Shader入门精要》时写有如下总结

使用替换的着色器渲染(官方解释)

一、 Camera.SetReplacementShader实战

二、Camera.SetReplacementShader总结

三、Camera.RenderWithShader实战

四、Camera.RenderWithShader总结


目的:理解RenderType的作用 ,当初学习《Shader入门精要》时写有如下总结

https://blog.csdn.net/qq_39574690/article/details/98440963

自定义着色器G

使用替换的着色器渲染(官方解释)

 

一些渲染效果需要使用一组不同的着色器渲染场景。例如,良好的边缘检测将需要具有场景法线的纹理,因此它可以检测表面方向不同的边缘。其他效果可能需要具有场景深度的纹理,依此类推。为此,可以使用替换后的所有对象着色器渲染场景。

可以通过使用Camera.RenderWithShaderCamera.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

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值