Shader学习光照模型,高光

简单的逐像素光照shader,这个只用于练习的。

Shader "Custom/05-frament Vertex" 
{
	   Properties
	   {
		 _Diffuse("DiffuseColor",Color)=(1,1,1,1)
	   }
	   SubShader
	   {
	   
		  pass
		  {
			  Tags{"LightMode"="ForwardBase"}
			  CGPROGRAM
			  #include "Lighting.cginc" //引入light 的库  
              #include "UnityCG.cginc"  
			  #pragma fragment frag
			  #pragma vertex vert
			  float4  _Diffuse; //使用属性 需要在这里再声明
		 
			  struct a2v
			  {
				 float4 vertex:POSITION;
				 float3 normal:NORMAL;
			  };

			  struct v2f
			  {
				float3 NormalDir:COLOR;
				float4 position:SV_POSITION;
			  };

			  v2f vert(a2v v)
			  {
				v2f f;
			    f.position=UnityObjectToClipPos(v.vertex) 
			    f.NormalDir= UnityObjectToWorldNormal(v.normal);
 
			  	return f;
			  }
//逐像素 光照
			  float4 frag(v2f f):SV_TARGET
			  {	
				   float3 LightDir=normalize(_WorldSpaceLightPos0.xyz);
				   float3 NormalDir=normalize(f.NormalDir);
				   float3 Ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
				   float3 diffuse=_LightColor0.rgb*max(0,dot(NormalDir,LightDir))*_Diffuse.rgb;
				   float3 newColor=Ambient+diffuse;//环境光+漫反射
				   return float4(newColor,1);
			  }
			  
			  
			  ENDCG
		  }
	   }

	   Fallback "VertexLit"
}

UnityObjectToClipPos(v.vertex) 这个是 把模型顶点坐标转换到裁剪空间里

UnityObjectToWorldNormal(float3 normal) 把模型的法线信息转换到世界坐标系里去。-

 

漫反射光照计算公式(兰伯特光照模型):

diffuse=_LightColor0.rgb*Color.rgb*saturate(dot(normal,LightDir));

其中 _LightColor0是 内置光照变量,默认是场景中的方向光照,物体法线,物体法线就是垂直于物体的线。

Color是自己定义的属性,saturate 相当于max(0,dot(N,L));

 

关于点积

点积:a.b=|a|*|b|*cosθ ; 由于方向向量 模 都为1,因此 dot(a,b)=1*1*cosθ。它的几何意义是 b在a方向上的 投影。 

 

当夹角>90° 时,就是背光,cos>90°都是小于0的(90°~270°),0在颜色里就是黑色,代表没有任何的RGB值。

缺点就是 >90的地方 都是黑的看不到模式的细节。改善可以使用半兰伯特模型,公式是 dot(N,L)*0.5 +0.5 N:法线方向,L:光线方向;

float3 LightDir=normalize(_WorldSpaceLightPos0.xyz);
float3 NormalDir=normalize(f.NormalDir);
float3 Ambient=UNITY_LIGHTMODEL_AMBIENT.rgb;
float3 diffuse;
diffuse=_LightColor0.rgb*max(0,dot(NormalDir,LightDir))*_Diffuse.rgb;

在Vert中对每个顶点着色,叫逐顶点,

放在frag中对每个像素着色,叫逐像素,计算更加密集,越消耗性能,得到的质量越好。

当定点法线 位于迎光面的时候,它的法线跟光的夹角是最小的时候,取得的值最大。

 

 

关于 光线衰弱以及 阴影的处理

 可以使用     #pragma multi_compile_fwdbase 以及  Tags{"LightMode"="ForwardBase"}

这样 可以 使用Unity内置的一些 宏, 告诉Unity,帮我们准备好下面要使用的一些变量信息;

只有这样 ,才可以使用一些内置宏。

 

在v2f 结构体 最后 一行, 添加SHADOW_COORDS(x) 这个x是最后一个通道的编号,这样 阴影信息可以存储在这个通道里。

在顶点作色器里  使用   TRANSFER_SHADOW(o); 使用上面的通道,转换模型阴影信息。

在片元着色器中 使用                UNITY_LIGHT_ATTENUATION(atten, i, worldPos); 可以得到 atten,它是光照衰弱系数,有了它 就可以得到 衰弱后的光照了,

fixed4(ambient + (diffuse + specular) * atten, 1.0);

 


高光的计算

物体的高光,

物体高光是我们视角看到的最亮的部分,

它的计算当然和视角有关,另一个和它有关的就是它的法线信息;还有一个就是光照的方向;

它的公式就是 Cspecular=max(0,dot(NormalDir,HalfDir))*SpecularColor;

这里的 HalfDir= normalize(ViewDir+LightDir);  normalize是 归一化,要得到任何单位方向,都需要把它们归一化。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值