shader学习之路(1)- half lambert

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

未启用/启用half-lambert算法(右側为启用)
如今我们来看看怎么实现这个算法,首先由于vs对shaderkeyword高亮支持并不太好(联网工具包中的shader高亮插件事实上还行)。所以能够用引擎自带的mono dev或者sublime text来编写Cg文件,这个看大家个人喜好了,有空我会介绍下vs和sublime text对shaderkeyword高亮的设置。
打开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,化石(编) 


posted on 2018-01-24 13:29  yjbjingcha  阅读(222)  评论(0编辑  收藏  举报

导航