Unity Shader零基础入门3:逐像素光照、Blinn-Phong、透明度

逐顶点光照与逐像素光照:

上一篇教程中光照在顶点函数中处理,处理好了再传输给片元函数,片元函数仅仅只是把颜色返回了一下。这种光照模式称为逐顶点光照。由于顶点很少,只在顶点函数中执行这些功能执行次数也较少,因此更节约性能,但同时效果也更差。

而如果在片元函数中处理光照(逐像素光照),则是相反-更耗费性能但效果也更好。如下图,逐像素光照会更加细腻和精准。

有一些量需要在顶点函数中获得,通过结构体将这些量传递到片元函数即可。

 Blinn-Phong光照模型:
之前的高光使用的是Blinn光照模型。但平时主要使用的是Blinn-Phong光照模型,高光区更大更亮一些。
高光颜色=直射光颜色*pow(max(cosθ,0),高光系数),公式看起来和之前一样,和之前的区别是θ不是反射光和视野方向的夹角,而是法线与(平行光和视野方向的平分线)的夹角。平行光和视野方向的平分线指光源方向和视野方向的夹角的中心的那个方向,计算上只需要将两个方向的单位向量相加即可得到(不一定要除2,因为数值整体的变大变小不改变方向)。

透明度:

之前说直接修改片元函数返回的值中的阿尔法值并不能直接修改透明度,这是因为还需要添加另外几句语句来改变渲染队列等才能让透明度生效。具体在代码中展示。

制作Shader:

新建一个Shader文件,改内容为如下:

Shader "Tutorial/03Fragment" {
	Properties{
			//漫反射颜色
			_Diffuse("Diffuse Color",Color)=(1,1,1,1)
			//高光系数
			_Gloss("Gloss",Range(8,200))=10
			//高光颜色
			_Specular("Specular color",Color)=(1,1,1,1)
			//阿尔法值,用来调整物体显示的透明度
			_AlphaScale("AlphaScale",Range(0,1))=1
	}

	SubShader{
			//在pass块之前写入,可控制多个pass块
			Tags{
				"Queue"="Transparent" //控制透明度需要。选择渲染队列,有透明度的会最后渲染
				"IngnoreProjector"="True" //控制透明度需要。忽略投影
				"RenderType"="Transparent"//控制透明度需要。用于按照规则替换不同shader显示
				}
		
		pass{
			ZWrite Off //控制透明度需要。无需深度缓冲
			Blend SrcAlpha OneMinusSrcAlpha //控制透明度需要。正常模式(透明度混合) 

			Tags{ "LightMode"="ForwardBase" }
			CGPROGRAM
			#include "Lighting.cginc"
			half _Gloss;
			fixed4 _Specular;
			fixed4 _Diffuse;
			//因为透明度只需要0-1,这里用fixed定义即可。
			fixed _AlphaScale;
			//声明顶点函数名为vert
			#pragma vertex vert
			//声明片元函数名为frag
			#pragma fragment frag 
			
			struct a2v{
				float3 normal:NORMAL;
				float4 vertex:POSITION;
			};

			struct v2f{
				float4 position:SV_POSITION;
				//用于将世界空间下的法线从顶点函数传递到片元函数
				//TEXCOORD含义为纹理坐标。TEXCOORD和COLOR都可以加不同数字以便区分同类型的变量。
				float3 worldNormal:TEXCOORD0; 
				//用于将世界空间下的顶点坐标从顶点函数传递到片元函数
				//上面的position是在剪切空间的顶点坐标,这里的在世界空间
				float3 worldVertex:TEXCOORD1;
			};

			v2f vert(a2v v){
				v2f f;
				//将顶点坐标转换到剪切空间
				f.position= mul(UNITY_MATRIX_MVP,v.vertex);
				//将法线转换到世界空间,转换法线与转换普通向量不同,需要左乘(float3x3)unity_WorldToObject
				f.worldNormal=mul(v.normal,(float3x3)unity_WorldToObject);
				//将顶点坐标转换到世界空间
				f.worldVertex=mul(unity_ObjectToWorld,v.vertex).xyz;
				//传递到片元函数
    			return f;
			}
			float4 frag(v2f f):SV_TARGET{
				//取得环境光
				fixed3 ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				//获得世界空间下法线单位向量方向
				fixed3 normalDir=normalize(f.worldNormal) ;
				//第一个直射光的位置(被照射点接收到的光的方向)
				fixed3 lightDir=normalize( _WorldSpaceLightPos0.xyz);
				//得到漫反射颜色
				fixed3 difuse= _LightColor0.rgb*max(dot(normalDir,lightDir),0)*_Diffuse.rgb;
				//得到反射光方向
				fixed3 reflectDir= normalize(reflect(-lightDir,normalDir));
				//视野方向
				fixed3 viewDir= normalize(_WorldSpaceCameraPos.xyz-f.worldVertex);
				//平行光方向和视野方向的平分线的方向
				fixed3 halfDir=normalize(lightDir+viewDir);
				//高光,使用了Blinn-Phong光照模型
				fixed3 specular=_LightColor0.rgb*_Specular.rgb*pow(max(0,dot(normalDir,halfDir)),_Gloss);
				//将漫反射、环境光、高光相加
				fixed3 tempColor=difuse+ambient+specular;
				//得到最终颜色。阿尔法值使用_AlphaScale。
				return fixed4(tempColor,_AlphaScale);
			}
			ENDCG

		}
	}

	Fallback "VertexLit"
}

然后给一个胶囊体添加新材质,之后更换这个新Shader(更换Shader的方法之前讲过)。可以将显示的胶囊和上一期的逐顶点光照、Blinn光照模型的胶囊对比一下:

也可以在面板中调整透明度:

猜你喜欢

转载自blog.csdn.net/qq_21315789/article/details/125434408