图形学入门--实现phong光照

1、镜面反射模型

光入射的角度L向量与向量N之间的夹角与反射光R向量与向量N之间的夹角是相同的,当向量R与相机向量V重合的时候,就说明光线被全部照进了人眼。入射光线L与反射光线R、向量N之间的交点是最亮的,如果稍微偏离,亮度会衰减。所以要求得镜面反光,不仅要求得R向量,还要求得V向量,相机的向量。求得R和V之间的角度,就可以求得L、V、R、N交界处是否应该高亮。如果使用点积来计算,当R向量远离V向量过后,只要角度不大于90度,数值总是大于0的。实际上,亮度的衰减并不是按住V和R角度的线性变化来进行的。如果角度稍微偏离一点,亮度衰减非常大,角度再稍微大一点,亮度几乎就可以衰减为0了。只有这样,才能得到高光的镜面反射光。下面的向量长度都不一致,真正使用的时候需要将其规范化,将长度都改为1,这样才能正确计算。



2、Cg reflect函数

N:顶点的法向量

I:入射光的向量,从光源指向顶点

R=Reflect(I,N)


Shader "Custom/MySpecular" {

	Properties{
		_SpecularColor("Specular",color)=(1,1,1,1)
	}

	SubShader{
		pass {

		tags{ "LightMode" = "ForwardBase" }

		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "unitycg.cginc"
		#include "lighting.cginc"

		float4 _SpecularColor;
		struct v2f {
			float4 pos:POSITION;
			fixed4 color : COLOR;
		};

		v2f vert(appdata_base v) {
			v2f o;
			o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
			float3 N = normalize(v.normal);
			float3 L = normalize(_WorldSpaceLightPos0);

			N = mul(float4(N,0), _World2Object).xyz;
			N = normalize(N);

			//Diffuse Color
			float ndotl = saturate(dot(N, L));
			o.color = _LightColor0*ndotl;


			//Specular Color
			//光的位置指向顶点
			float3 I = -WorldSpaceLightDir(v.vertex);
			float3 R = reflect(I,N);
			//摄像机转向顶点
			float3 V = WorldSpaceViewDir(v.vertex);
			R = normalize(R);
			V = normalize(V);
			//模拟当物体特别亮,当稍微一转就没有那么亮的物理现象
			float specularScale = pow(saturate(dot(R,V)),4);
			o.color.rgb += _LightColor0*specularScale;
		
			return o;
		}


		fixed4 frag(v2f IN) :COLOR{
			//环境光照
			return IN.color + UNITY_LIGHTMODEL_AMBIENT;
		}
			ENDCG
	}
	}

}



也可以着色,但是效果不明显:



3、

衰减变化

修改方向光的强度,让顶点光的变化更强烈一些



将强度作为一个变量,通过调整变量来调节光的强度

Shader "Custom/MySpecular" {

	Properties{
		_SpecularColor("Specular",color)=(1,1,1,1)
		_Shininess("Shininess",range(1,64))=8
	}

	SubShader{
		pass {

		tags{ "LightMode" = "ForwardBase" }

		CGPROGRAM
		#pragma vertex vert
		#pragma fragment frag
		#include "unitycg.cginc"
		#include "lighting.cginc"

		float4 _SpecularColor;
		float _Shininess;

		struct v2f {
			float4 pos:POSITION;
			fixed4 color : COLOR;
		};

		v2f vert(appdata_base v) {
			v2f o;
			o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
			float3 N = normalize(v.normal);
			float3 L = normalize(_WorldSpaceLightPos0);

			N = mul(float4(N,0), _World2Object).xyz;
			N = normalize(N);

			//Diffuse Color
			float ndotl = saturate(dot(N, L));
			o.color = _LightColor0*ndotl;


			//Specular Color
			//光的位置指向顶点
			float3 I = -WorldSpaceLightDir(v.vertex);
			float3 R = reflect(I,N);
			//摄像机转向顶点
			float3 V = WorldSpaceViewDir(v.vertex);
			R = normalize(R);
			V = normalize(V);
			//模拟当物体特别亮,当稍微一转就没有那么亮的物理现象
			float specularScale = pow(saturate(dot(R,V)),4);
			o.color.rgb += _SpecularColor*specularScale;
		
			return o;
		}


		fixed4 frag(v2f IN) :COLOR{
			//环境光照
			return IN.color + UNITY_LIGHTMODEL_AMBIENT;
		}
			ENDCG
	}
	}

}




4、


改变高光的颜色,查看着色的效果


高光不平滑的原因是,所有的代码都放在了顶点级,放在片段级就平滑了



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值