开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天,[点击查看活动详情]
前言
在之前的文章中,对漫反射光照模型进行了介绍,核心是利用兰伯特定律来描述。本篇介绍光照模型中的高光反射(也就是我们经常说的镜面反射),同样使用Unity游戏引擎来实现。
高光反射的由来
在介绍高光反射之前,我们先来看看当一束光线从光源发出,照射到物体表面的这一系列过程都发生了什么?光线发出会跟物体发生相交,而相交的结果有两种:散射和吸收。这里吸收我们暂时不考虑。光线经过物体表面散射之后,也会有两种结果:即要么散射到物体内部,要么散射到物体的外部。散射到物体内部的现象被称为折射,而到外部的部分就形成了反射。高光反射就是用来描述散射到物体外部的这一部分辐射量的。
利用Phone模型计算高光
知道了高光反射的由来,最后需要将其转换为一个数学问题。这个时候就该Phone模型上场了:
specular = lightColor * specularColor * max(0,v·r)^gloss //gloss为光泽度,可以理解为一个常数
从公式我们可以看出模型需要的信息包括观察方向和反射方向,而反射方向的计算方式又需要光源方向和物体表面的法线方向,所以为了利用Phone模型来描述高光反射,我们总共需要四个信息,即物体表面法线、观察方向、光源方向、反射方向。
在unity中的具体实现
有了前面的理论知识之后,来看看在Unity引擎中如何具体实现。
- 1、在Project面板右键创建一个Unlit Shader,将其命名为Specular。
- 2、选中刚刚创建的Specular,右键创建一个Material。
- 3、在Hierarchy面板创建一个Sphere,并将第2步创建的Material拖拽赋值到Sphere上。
- 4、使用脚本IDE打开第一步创建的Shader,添加代码如下:
Shader "Unlit/Specular"
{
Properties
{
//漫反射颜色
_Diffuse("Diffuse",Color)=(1.0,1.0,1.0,1.0)
//高光颜色
_Specular("Specular",Color)=(1.0,1.0,1.0,1.0)
//光泽度 值越大高光点越小
_Gloss("Gloss",Range(1,90)) = 20
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "UnityLightingCommon.cginc"
float4 _Diffuse;
float4 _Specular;
float _Gloss;
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float4 posWS:TEXCOORD0;
float3 nDirWS:TEXCOORD1;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld,v.vertex);
o.nDirWS=UnityObjectToWorldNormal(v.normal);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 nDirWS = i.nDirWS;
float3 lDirWS = _WorldSpaceLightPos0.xyz;
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 hDirWS = normalize(vDirWS + lDirWS);
float3 rDir = reflect(-lDirWS,nDirWS);
float nDotl = dot(nDirWS,lDirWS);
float lambert = max(0,nDotl);
//构建Phong光照模型
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 diffuse = _LightColor0.rgb * _Diffuse.rgb * lambert;
float vDotr = dot(vDirWS,rDir);
float phone = _LightColor0.rgb * _Specular.rgb * pow(max(0,vDotr),_Gloss);
float3 col = ambient + diffuse + phone;
return fixed4(col,1.0);
}
ENDCG
}
}
}
- 5、查看效果。
最后
Shader中的颜色参数设置比如漫反射颜色,高光颜色,光泽度等参数可以在材质面板中自由设置。本篇主要介绍了Phone光照模型中的高光是如何描述的。OK,本篇就到这里。