shader学习之路(1)- half lambert

在学习这个shader之前先提个常用概念,即光照模型,LightModel(光照模型)即是对于物体怎么对打在其上的光做出视觉反应的数学模型,意即表达物体对光反应产生的视觉效果与入射光、物体表面属性等数值相关联的数学表达。
大致了解了光照模型的概念,接下来介绍下今天的主角,Half Lambert模型,该模型是Valve在开发经典游戏《Half-Life(半衰期)》(半条命这个译名真是后无古人的误翻啊……)是发明的,在以前的游戏中,一旦模型背对着光源,模型表面的亮度会立刻降低,使得整个模型显得平面化,毕竟游戏世界并非像现实中有各种漫散射光能照亮背光的一面,所以half-lambert算法提高了物体在背对光源时的亮度,由于其并非根据真实物理推算出来的结果,而仅仅是一种视觉感受的提升,所以其实现方式并不复杂,很多shader入门书籍都介绍过这种算法,不必担心完全看不懂。

未启用/启用half-lambert算法(右侧为启用)
现在我们来看看怎么实现这个算法,首先因为vs对shader关键字高亮支持并不太好(联网工具包中的shader高亮插件其实还行),所以可以用引擎自带的mono dev或者sublime text来编写Cg文件,这个看大家个人喜好了,有空我会介绍下vs和sublime text对shader关键字高亮的设置。
打开unity3d,在project栏中的Assets下建立Materials Shader两个文件夹(良好的资源管理是开发工程的必要前提),在shader中创建一个surface shader并将之命名为halfLambert。

打开shader文件,可以看到默认的属性栏Properties,这下面的变量不仅要在下面的代码中使用,同时也能在引擎的inspector中进行调整。

现在我们将其修改为如下属性:

接下来在SubShader块中,可以看到这样一段定义

这是定义shader所使用的光照模型,因为我们是自定义模型,所以要改为

还记得先前在Properties定义的三个变量吗,只在Properties中声明的话虽然能在inspector中看到,但还不能在subshader中使用,所以在SubShader块中需要再次声明,如下图

接下来我们开始编写该模型的主要部分,如下

这个函数的命名是有规则的,Lighting+模型名,该模型名称就是你刚才是在#pragma surface中命名的模型名称,这样unity就能自行编译链接该shader所使用的模型。
整个half-lambert模型的关键在于此
Lambert模型中的difLight在dot()方法下,处于[0,1]的范围中,因此hLambert的范围就在[0.5,1]中,提高了整体的漫反射值,其值的变化如下

剩余的则是surf代码

写完了shader代码后,现在需要将shader使用在物体上,在Material中建立一个新的Material,并将该shader拖入其中

在场景中建立一个Sphere后,将该Material赋予其中

最后效果如图,右侧是未使用half-lambert算法的效果,可以看到half-lambert的确是明显提升了物体材质表面的亮度,在视觉上更加明亮。


完整代码如下:
Shader "Custom/halfLambert" {
	Properties {
		_EmissiveColor("Emissive Color", Color) = (1, 1, 1, 1)
		_AmbientColor("Ambient Color", color) = (1, 1, 1, 1)
		_SliderValue("Slider", Range(0,10)) = 2.5
	}
	SubShader {
		Tags { "RenderType"="Opaque" }
		LOD 200
		
		CGPROGRAM
		// Physically based Standard lighting model, and enable shadows on all light types
		#pragma surface surf HalfLambert

		// Use shader model 3.0 target, to get nicer looking lighting
		#pragma target 3.0

		float4 _EmissiveColor;
		float4 _AmbientColor;
		float _SliderValue;

		inline float4 LightingHalfLambert(SurfaceOutput s, fixed3 lightDir, fixed atten)
		{
			float difLight = max(0, dot(s.Normal, lightDir));
			float hLambert = difLight * 0.5 + 0.5;

			float4 col;
			col.rgb = s.Albedo * _LightColor0.rgb * (hLambert * atten * 2);
			col.a = s.Alpha;
			return col;
		}

		struct Input
		{
			float2 uv_MainTex;
		};
		
		void surf(Input IN, inout SurfaceOutput o)
		{
			float4 c;
			c = pow((_EmissiveColor + _AmbientColor), _SliderValue);

			o.Albedo = c.rgb;
			o.Alpha = c.a;
		}
		ENDCG
	}
	FallBack "Diffuse"
}


P.S 初次写有关3d图形学的博客,时间仓促,还有好多内容没有说明白,还请各路大佬多多指导!
参考书目:
1.Unity Shaders and Effects Cookbook - (美)Kenny Lammers
2.Unity3d shader 编程 - 98jy.net,化石(编) 


你可能感兴趣的:(Shader学习之路)