Unity Shader - 顶点着色器与片段着色器之间数据的传递方式

在顶点着色器函数中,顾名思义,vert函数处理的对象是一个个的独立的顶点,在完成对顶点的位置、法线、纹理坐标等数据的处理之后,会将相关的数据传递给片段着色器继续进行处理。需要注意的是,frag函数并非原封不动的对vert函数传递过来的数据进行接收,而是会对其进行插值运算。因为,片段着色器处理的对象是每一个像素点,顶点着色器传递过来的顶点信息显然无法满足片段着色器的处理需求,所以片段着色器会将处于每一个三角形中的像素点相对于该三角形的三个顶点进行插值计算。

我们可以通过简单shader脚本进行如下验证。

首先,我们建立如下场景,一个立方体Cube,一个平面Plane,一个位于(0,0,0)点的球体Sphere。


接着,我们在Shader中进行如下算法的实现,当立方体中的顶点距离(0,0,0)点小于5的时候,设置顶点颜色为绿色;当立方体中的顶点距离(0,0,0)点大于5的时候,设置顶点颜色为红色:

Shader "Custom/SetColorInVert" {
	Properties {
      	_ZeroPoint ("ZeroPoint", Vector) = (0, 0, 0, 0)
		_Distance ("Distance", Float) = 5.0
		_ColorNear ("Color_Near", Color) = (0.0, 1.0, 0.0, 1.0)
		_ColorFar ("Color_Far", Color) = (1.0, 0.0, 0.0, 1.0)
	}
	SubShader {
		Pass
		{
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4 _ZeroPoint;
			uniform float _Distance;
			uniform float4 _ColorNear;
			uniform float4 _ColorFar;
			
			struct vertexInput
			{
				float4 vertex : POSITION;
			};
			
			struct vertexOutput
			{
				float4 pos : SV_POSITION;
				float4 posInWorld : TEXCOORD0;
				float4 col : COLOR;
			};
			
			vertexOutput vert(vertexInput input)
			{
				vertexOutput output;
				output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
				output.posInWorld = mul(_Object2World, input.vertex);
				
				float dist = distance(output.posInWorld, _ZeroPoint);
				
				if(dist < _Distance) 
				{
					output.col = _ColorNear;
				}
				else
				{
					output.col = _ColorFar;
				}
				
				return output;
			}
			
			float4 frag(vertexOutput input) : COLOR
			{			
				return input.col;
			}
									
			ENDCG
		}
	} 
}
将该shader应用到Cube上之后,我们从远方慢慢在X方向上移动立方体接近(0,0,0)点,依次得到如下的效果:

(1)所有顶点都距离原点大于5,因此每个顶点都为红色,因此,每个三角形的顶点都为红色,三角形内部的每个像素进行插值之后也都为红色。

(2)右下角的顶点距离原点小于5,可以看到右下角顶点的颜色已经变为了绿色,所有以此类顶点为顶点的三角形中的像素点出现了渐变的效果:越靠近绿色顶点的像素点颜色越偏向绿色,越靠近红色顶点的像素点的颜色越偏向红色。

(3)进一步的在X方向上靠近(0,0,0)点,右上方的顶点距离(0,0,0)点的距离也开始小于5,因此有更多的以此顶点为顶点的三角形开始呈现渐变效果。

(4)进一步的在X方向上靠近(0,0,0)点,只有左上方的顶点距离(0,0,0)点的距离大于5,因此可以看到所有以绿色顶点为顶点的三角形内的像素点都呈现为绿色,不再有渐变效果。

(5)最终所有的顶点距离(0,0,0)点的距离都小于5,所以所有的顶点的颜色都为绿色,所有的三角形内的像素点经过插值依然为绿色。


我们再对上面的shader进行改造,将计算与(0,0,0)点的距离的方法放到frag函数中,也就是计算每一个像素点距离(0,0,0)点的距离:

Shader "Custom/SetColorInFrag" {
	Properties {
      	_ZeroPoint ("ZeroPoint", Vector) = (0, 0, 0, 0)
		_Distance ("Distance", Float) = 5.0
		_ColorNear ("Color_Near", Color) = (0.0, 1.0, 0.0, 1.0)
		_ColorFar ("Color_Far", Color) = (1.0, 0.0, 0.0, 1.0)
	}
	SubShader {
		Pass
		{
			CGPROGRAM
			
			#pragma vertex vert
			#pragma fragment frag
			#include "UnityCG.cginc"

			uniform float4 _ZeroPoint;
			uniform float _Distance;
			uniform float4 _ColorNear;
			uniform float4 _ColorFar;
			
			struct vertexInput
			{
				float4 vertex : POSITION;
			};
			
			struct vertexOutput
			{
				float4 pos : SV_POSITION;
				float4 posInWorld : TEXCOORD0;
			};
			
			vertexOutput vert(vertexInput input)
			{
				vertexOutput output;
				output.pos = mul(UNITY_MATRIX_MVP, input.vertex);
				output.posInWorld = mul(_Object2World, input.vertex);
				
				return output;
			}
			
			float4 frag(vertexOutput input) : COLOR
			{				
				float dist = distance(input.posInWorld, _ZeroPoint);
				
				if(dist < _Distance) 
				{
					return _ColorNear;
				}
				else
				{
					return _ColorFar;
				}
			}
									
			ENDCG
		}
	} 
}

将该shader应用到Cube上之后,我们再次从远方慢慢在X方向上移动立方体接近(0,0,0)点,依次得到如下的效果:


从上面的几幅图中看以看出,我们将计算颜色的方法放到frag函数中之后,每个像素点的颜色完全由该函数中的计算结果来决定,而不再是对顶点穿过来的颜色值进行插值得到的结果。

猜你喜欢

转载自blog.csdn.net/chunxiao860815/article/details/50550155