Unity_Shader学习(三)我的第一个Shader

这篇博客介绍了如何在Unity中编写第一个Shader,包括基本的顶点着色器和片元着色器的声明与实现。通过在Properties中定义变量增加可配置性,并讲解了Unity的一些内置变量和函数的使用,如appdata_base、WorldSpaceViewDir等,帮助理解Shader的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

根据我们上一次学习的Shader的结构,我们来编写我们的第一个Shader:

Shader "Custom/TestShader" {
	Properties{
		
	}

	SubShader{
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			float4 vert(float4 v:POSITION):SV_POSITION{
				return UnityObjectToClipPos(v);
			}

			fixed4 frag():SV_Target{
				return fixed4(1,1,1,1);
			}

			ENDCG
		}
	}
}

在代码都在Pass块中,Pass中所有代码都必须在CGPROGRAM与ENDCG之间:

CGPROGRAM

XXX

ENDCG

紧接着的是两个#pragma语句,#pragma vertex vert是声明顶点着色器函数的语句,而#pragma fragment frag是声明片元着色器的语句,其中的vert与frag是两个函数的函数名,是可变的。

#pragma vertex name1
#pragma fragment name2

然后是vert函数与frag函数的实现,vert输入是一个float4类型的数,它的语义是POSITION即一个顶点位置。它的返回值也是一个float4类型的数,语义为SV_POSITION即裁剪空间的一个坐标。内部的处理是UnityObjectToClipPos(v),是把顶点位置从模型空间变换到裁剪空间,等同于mul(UNITY_MATRIX_MVP, v)。frag函数没有输入,它的输出是一个fixed4类型的数,语义为SV_TARGET,是指把用户输出的颜色存储到一个渲染目标中。

			float4 vert(float4 v:POSITION):SV_POSITION{
				return UnityObjectToClipPos(v);
			}

			fixed4 frag():SV_Target{
				return fixed4(1,1,1,1);
			}

这样我们就成功编写了最简单的Shader,在Unity中创建一个新的材质,采用我们的这个Shader,然后将这个材质拖动到Cube和Sphere上,就可以看到效果了:

 

 

但是这时我们会发现很多的问题,比如我们顶点函数获取的输入只有一个顶点坐标位置,能处理的信息非常有限,而且我们的Properties还是空的,所以我们要学习一个更常用的框架结构。

Shader "Custom/SimpleShader" {
	Properties{
		_Color("Color Tint",Color) = (1,1,1,1)
	}

	SubShader{
		Pass{
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag

			fixed4 _Color;

			struct a2v{
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 texcoord:TEXCOORD0;
			};

			struct v2f{
				float4 pos:SV_POSITION;
				fixed3 color:COLOR0;
			};

			v2f vert(a2v v){
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
				return o;
			}

			fixed4 frag(v2f i):SV_TARGET{
				fixed3 c = i.color;
				c *= _Color.rgb;
				return fixed4(c,1.0);
			}

			ENDCG
		}
	}

	FallBack "Diffuse"
}

相比于我们的TestShader,SimpleShader中做了如下改动:

在Properties中定义了一个变量_Color

vert与frag函数的输入输出

vert与frag函数的内部处理

 

 

Properties中定义的变量_Color,其名字是Color Tint,类型是Color,用四维数(1,1,1,1)赋值。注意句末不要加分号!

_Color("Color Tint",Color) = (1,1,1,1)

 

vert函数的输入是一个新定义的结构a2v,其含义是application(应用)到vertex(顶点处理)。返回值为v2f,其含义为vertex(顶点处理)到fragment(片元处理)。

在a2v中定义了顶点位置vertex,其语义为POSITION,就是TestShader中vert函数的输入。然后我们还定义了 法线normal:NORMAL 与 第一套纹理坐标texcoord:TEXCOORD。

在v2f中定义了裁剪空间坐标pos:SV_POSITION及存储颜色信息的color:COLOR0。

			struct a2v{
				float4 vertex:POSITION;
				float3 normal:NORMAL;
				float4 texcoord:TEXCOORD0;
			};

			struct v2f{
				float4 pos:SV_POSITION;
				fixed3 color:COLOR0;
			};

 

vert函数中计算了裁剪空间的坐标并传递给v2f结构中的pos,然后将法线分量范围从[-1,1]变换到[0,1],传递给v2f结构中的color。

frag函数中根据vert中法线计算得到的color与属性中的_Color计算,注意_Color需要在Pass中声明并且名称与Properties中的一样。

			v2f vert(a2v v){
				v2f o;
				o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
				o.color = v.normal * 0.5 + fixed3(0.5,0.5,0.5);
				return o;
			}

			fixed4 frag(v2f i):SV_TARGET{
				fixed3 c = i.color;
				c *= _Color.rgb;
				return fixed4(c,1.0);
			}

这样我们得到了一个具有一定通用性结构的Shader,可以观察其效果:

 

最后,我们来学习一下Unity一些内置变量及函数:

appdata_base  用于顶点着色器的输入  包含顶点位置,顶点法线,第一组纹理坐标

appdata_tan  用于顶点着色器的输入  包含顶点位置,顶点切线,顶点法线,第一组纹理坐标

appdata_full  用于顶点着色器的输入  包含顶点位置,顶点切线,顶点法线,四组(或更多)纹理坐标

appdata_img  用于顶点着色器的输入  包含顶点位置,第一组纹理坐标

v2f_img  用于顶点着色器的输出,片元着色器的输入  包含裁剪空间中的位置,纹理坐标

 

float3 WorldSpaceViewDir(float4) 输入一个模型空间的顶点位置,返回其 世界空间 中 从该点到摄像机 的方向

float3 ObjSpaceViewDir(float4) 输入一个模型空间的顶点位置,返回其 模型空间 中 从该点到摄像机 的方向

float3 WorldSpaceLightDir(float4) 输入一个模型空间的顶点位置,返回其 世界空间 中 从该点到光源 的方向(仅在前向渲染中)

float3 ObjSpaceLightDir(float4) 输入一个模型空间的顶点位置,返回其 模型空间 中 从该点到光源 的方向(仅在前向渲染中)

float3 UnityObjectToWorldNormal(float3) 用于将法线从模型空间变换到世界空间

float3 UnityObjectToWorldDir(float3) 用于将方向矢量从模型空间变换到世界空间

float3 UnityWorldToObjDir(float3) 用于将方向矢量从世界空间变换到模型空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我只知道我要大开杀戒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值