[Unity-Shader]Shader学习-漫反射材质

目录

一、逐顶点兰伯特模型光照

知识:

一些方法:

 二、逐像素兰伯特模型光照

 三、半兰伯特模型光照

一、逐顶点兰伯特模型光照

即为:

屏幕上对应点的颜色=(光的颜色*物体颜色) *max(0,该点的法向量*(点乘dot)该点的光照方向)

当光照方向与顶点法线方向的夹角小于90度时,物体该点材质可见,当大于等于90度时,物体该点的材质不可见(黑色)。

知识:

当两个向量的dot大于0时:夹角小于90度

当两个向量的dot等于0时;夹角等于90度

当两个向量的dot小于0时;夹角大于90度

一些方法:

UnityObjectToWorldNormal()        //把物体的法线坐标换算到世界坐标下
normalize()                       //把任何一个向量变为单位向量
dot()                             //点乘
max()
//下面要有#include "Lighting.cginc"才能找到
_WorldSpaceLightPos0               //世界坐标下的光线坐标
_LightColor0                       //光线的颜色

 本节使用的Unity自带结构体:

struct appdata_full {
    float4 vertex : POSITION;    //顶点坐标
    float4 tangent : TANGENT;    //切线
    float3 normal : NORMAL;      //法线
    float4 texcoord : TEXCOORD0;    //第一纹理坐标
    float4 texcoord1 : TEXCOORD1;//第二纹理坐标
    float4 texcoord2 : TEXCOORD2;//第三纹理坐标
    float4 texcoord3 : TEXCOORD3;//第四纹理坐标
    fixed4 color : COLOR;        //顶点颜色
    UNITY_VERTEX_INPUT_INSTANCE_ID    //ID信息
};

代码: 

Shader "Custom/new5-2"
{
	Properties{
        //定义属性_Color
		_Color("color",Color)=(1,1,1,1)
		
		_Tex("2DTex",2D)="white"{}
	}
   SubShader
   {
	   pass
	   {
		   CGPROGRAM

		   #pragma vertex vert
		   #pragma fragment frag
            
            //引用Unity封装好的一些结构体
		   #include"UnityCG.cginc"
		   #include"Lighting.cginc"

		   float4 _Color;//声明一下_Color
		   sampler2D _Tex;
            
            
		   appdata_full vert(appdata_full v)
		   {
               //模型顶点坐标转屏幕坐标
			   v.vertex=UnityObjectToClipPos(v.vertex);
			   
               //获取法线坐标并转换成世界坐标下的法线坐标
               float3 worldNormal = UnityObjectToWorldNormal(v.normal);
    
               //光线的的单位坐标
			   float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
			   
               float num = dot(worldLight.xyz,v.normal.xyz);

			   num=max(0,num);
               //颜色
			   v.color=_LightColor0 * _Color * num;

			   return v;
		   }
		   
		   
		   float4 frag(appdata_full v/*获取结构体v中的法线等信息*/):SV_TARGET
		   {
			   float4 c = tex2D(_Tex,v.texcoord.xy)*v.color;//此tex2D无法在顶点着色器中使用
			   return c;
		   }

		   ENDCG
		   }
   }
   FallBack "Diffuse"
}

但是这种情况下我们发现此时虽然有了阴影效果,但是当我们转动小球时,阴影部分位置没有随着转动而改变,

向上转动后:

 二、逐像素兰伯特模型光照

 我们在逐顶点光照模型中达到的小球是这样的:

我们发现它的边缘阴影不是很流畅,我们想要让它平滑过渡,就可以使用逐像素模型

而产生这样效果的原因是我们在顶点着色器中写光照坐标和颜色等等的计算到了片元着色器中后可能就会有些许的不准确(误差),所以我们直接把这部分计算转移到片元着色器就可以了。

               //光线的的单位坐标
			   float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
			   
               float num = dot(worldLight.xyz,v.normal.xyz);

			   num=max(0,num);
               //颜色
			   v.color=_LightColor0 * _Color * num;

 操作后的效果:

 三、半兰伯特模型光照

即为:

Cdiffuse =(光的颜色*物体本身颜色) *(0.5*(法向量*世界光照)+0.5) 

注意:0.5*(法向量*世界光照)+0.5)计算范围

并且,在上面的基础上:最终颜色  = 环境光+Cdiffuse

#获取环境光强度的方法:UNITY_LIGHTMODEL_AMBIENT.xyz

在很多情况下,因为大多数事物都会向外界反射光线,比如墙体,所以我们不希望上面阴影的部分时完全看不见的,而是渐变的灰黑色,这时候我们就需要使用半兰伯特光照模型了。

代码:

Shader "Custom/new5-2"
{
	Properties{
        //定义属性_Color
		_Color("color",Color)=(1,1,1,1)
		
		_Tex("2DTex",2D)="white"{}
	}
   SubShader
   {
	   pass
	   {
		   CGPROGRAM

		   #pragma vertex vert
		   #pragma fragment frag
            
            //引用Unity封装好的一些结构体
		   #include"UnityCG.cginc"
		   #include"Lighting.cginc"

		   float4 _Color;//声明一下_Color
		   sampler2D _Tex;
            
            
		   appdata_full vert(appdata_full v)
		   {
			   v.vertex=UnityObjectToClipPos(v.vertex);
			   //世界坐标转屏幕坐标
			   return v;
		   }
		   
		   
		   float4 frag(appdata_full v/*获取结构体v中的法线等信息*/):SV_TARGET
		   {
		       //法向量
			   float3 worldNormal = v.normal;
			   //获取环境光
               float3 anbient = UNITY_LIGHTMODEL_AMBIENT.xyz;
			   //世界光照
			   float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
			   //计算范围
               float halfLamient = dot(worldNormal,worldLight)*0.5+0.5;
			   //计算反射强度
               float3 diffuse =_LightColor0.rgb * _Color *halfLamient;
			   //环境光加diffuse
               float3 c = anbient + diffuse;

			   return float4(c,1); 
		   }

		   ENDCG
		   }
   }
   FallBack "Diffuse"
}

上面代码的效果:

我们可以看到,在之前全黑的部分现在是渐变的灰黑色,而且当我们转动光的方向向上时:

 我们发现也是会跟着改变的。

现在我们想要图片也弄进去怎么办呢,我们只需要将最后的c与图片样式_Tex相乘即可(这里的图片需要用图片转换tex2D

//图片转换函数
tex2D(图片,采样方式)

 即:

c = c * tex2D(_Tex,v.texcoord.xy);

完整代码:

Shader "Custom/new5-2"
{
	Properties{
        //定义属性_Color
		_Color("color",Color)=(1,1,1,1)
		
		_Tex("2DTex",2D)="white"{}
	}
   SubShader
   {
	   pass
	   {
		   CGPROGRAM

		   #pragma vertex vert
		   #pragma fragment frag
            
            //引用Unity封装好的一些结构体
		   #include"UnityCG.cginc"
		   #include"Lighting.cginc"

		   float4 _Color;//声明一下_Color
		   sampler2D _Tex;
            
            
		   appdata_full vert(appdata_full v)
		   {
			   v.vertex=UnityObjectToClipPos(v.vertex);
			   //世界坐标转屏幕坐标
			   return v;
		   }
		   
		   
		   float4 frag(appdata_full v/*获取结构体v中的法线等信息*/):SV_TARGET
		   {
		       //法向量
			   float3 worldNormal = v.normal;
			   //获取环境光
               float3 anbient = UNITY_LIGHTMODEL_AMBIENT.xyz;
			   //世界光照
			   float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);
			   //计算范围
               float halfLamient = dot(worldNormal,worldLight)*0.5+0.5;
			   //计算反射强度 
               float3 diffuse =_LightColor0.rgb * _Color *halfLamient;
			   //环境光加diffuse
               float3 c = anbient + diffuse; 
			   c = c * tex2D(_Tex,v.texcoord.xy);
			   return float4(c,1); 
		   }

		   ENDCG
		   }
   }
   FallBack "Diffuse"
}

效果预览:

 灰常实用~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值