Article Directory
(23.3.16 Pick up knowledge again today, start reviewing from phong)
reference:
learn opengl
"Introduction to unityshader"
structure
Note that all the formulas in this article are light intensity and cannot be directly used in the shader, because the calculation of the reflected color is also required
In order to remember better, combine the two types of lighting to contrast and remember that
phong lighting consists of three parts, as shown in the figure
Ambient ambient light
slightly
Diffuse diffuse light
Diffuse lighting is not view-line dependent, only light and surface normal, so the result is like a map
The role of diffuse reflection is only to calculate the weakening light intensity according to the angle of incidence, nothing more:
C = −L ⋅ NC = -L NC=−L⋅N
L is the light vector, N is the normal vector
diff = max(dot(norm, lightDir), 0.0)
(The max function limits the dot product to [0, 1], and it cannot be illuminated if it is greater than 90 degrees, and it also avoids negative numbers)
That is, the diffuse intensity is proportional to the cosine of LN
Specular highlights
Wind
Highlights are only related to two vectors: the line of sight direction and the reflection direction (but the reflection vector is also calculated)
As shown in the figure, it seems that there are many vectors, but only two are really needed, V and R, but in order to achieve a bright spot (a small block), we need an exponential operation:
C = ( V ⋅ R ) g C = (V·R)^{g} C=(V⋅R)g
- V is the line of sight vector, R is the reflection vector, g is the gloss coefficient gloss/shininess (the bigger the more concentrated)
- In fact, this formula is also the highlight distribution of phong. When the roughness g is 1, its attenuation curve is a cos function [ 0 , π 2 ) [0,\frac{\pi}{2})[0,2p) part; then the difference in g can change the shape of the distribution, the smaller the g, the smoother the distribution, and the larger the steeper (power function)
- Since there is no energy conservation in PBR, when g is relatively small, the highlights will look too big and too bright
- The distribution of specular and diffuse with g=1 is different! Although they are all Gaussian distributions, they work in different ways. Diffuse is a directional light, and spec is a point light source.
spec = pow(max(dot(viewDir, reflectDir), 0.0), gloss)
(The purpose of the max function is to limit the dot product to [0, 1], avoiding the occurrence of negative numbers, but unfortunately, the direction of sight and reflection can be greater than 90 degrees, which is also the defect of phong)
R can be calculated by a special function reflect(N, -L) (whether this is specific has not yet been verified), the specific formula seems to be very troublesome, and will be added later
Blinn-Phong
bp no longer needs to calculate the reflection vector, and there
are only two vectors related to the half-way vector: normal, half-way vector (need to be calculated)
C = ( H ⋅ N ) g C=(H·N)^g C=(H⋅N)g
spec = pow(max(dot(halfDir,normal), 0.0), gloss)
(No matter how H changes, it will not be greater than 90 degrees, so the max here is completely fine, and the calculation of H is easier than R)
halfDir = normalize(lightDir + viewDir)
Comparison of the advantages and disadvantages of the two
Problems with phong
When the gloss is too small, the highlight area will be very large, which is not a problem in itself, but it will form a highlight fault at certain angles (usually looking at the ground along the light):
Reason: When we apply phong's highlight calculation, we will define the part of sight V and reflection R greater than 90 degrees as 0, which is to prevent negative numbers from appearing ( cos 12 0 ∘ = − 0.5 cos120^\circ = -0.5cos120∘=− 0.5 ), but in reality, the angle of V and R may be greater than 90 degrees:
this leads to a fault, because the highlights greater than 90 degrees disappear directly,
so blinn-phong is commonly used:
Both effects
Because both are empirical models, there are no advantages or disadvantages in terms of effect.
The only difference between the two is the calculation of highlights, so the difference in effect is only the highlight part: the
included angle of blinnphong is usually smaller than the included angle of phong, Therefore, when the highlight area is similar, the gloss of phong' will be much smaller;
even if the area is the same, the specular light of glossBlinn-Phong will be sharper than the Phong model
running speed
Generally speaking, blinn will be faster, (in terms of hardware implementation, which one is faster, R or H, has not yet been verified)
(Getting started: When the camera and the light source are far enough away from the model , blinn-phong will be faster, because H will be treated as a constant in hardware processing; when it is too close to be regarded as a constant, phong may be faster) Personally not
very Agree and understand: GPU will be optimized for this kind of thing? Also treated as a constant according to the distance, a bit exaggerated)
The problem of coexistence
1. Fresnel cannot be calculated (the empirical model will not be used in PBR)
2. Anisotropy (such as metal wire drawing) cannot be calculated (still not available)
because it is isotropic, fixed camera and Light source, the light will not change when the surface of the object rotates, but the anisotropic surface will change
Unity shader implementation
Shader "Unlit/phong"
{
Properties
{
_Diffuse ("Diffuse", Color) = (1,1,1,1)
_Specular ("Specular", Color) = (1,1,1,1)
_Gloss ("Gloss", Range(8,256)) = 20
}
SubShader
{
Pass
{
Tags {
"LightMode"="ForwardBase"}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc" //导入这个包是为了使用外源环境光_LightColor0,否则只能使用自己指定的环境光,可能会不自然
struct appdata
{
float4 vertex : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 vertex : SV_POSITION;
float3 w_Normal : TEXCOORD0;
float3 w_Pos : TEXCOORD1;
};
float4 _Diffuse;
float4 _Specular;
float _Gloss;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.w_Normal = UnityObjectToWorldDir(v.normal); //注意这两句的两种不同实现方法
o.w_Pos = mul(unity_ObjectToWorld, v.vertex).xyz;
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 w_Normal = normalize(i.w_Normal);
float3 w_LightDir = normalize(_WorldSpaceLightPos0.xyz);
float3 reflectDir = normalize(reflect(-w_LightDir,w_Normal));
float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.w_Pos.xyz);
float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;
float3 diff = _LightColor0.rgb * _Diffuse.rgb * max(dot(w_Normal, w_LightDir), 0.0);
float3 spec = _LightColor0.rgb * _Specular.rgb * pow(saturate(dot(reflectDir, viewDir)), _Gloss);
return fixed4(ambient + diff + spec , 1.0);
}
ENDCG
}
}
}