[ShaderLab] Understanding of Phong and Blinn-Phong lighting models

text

        (Copied a picture by hand)

Both Phong and Blinn-Phong lighting models are used to achieve the effect of light shining on the object, and the object performance produces a highlight part. The two models are also very similar. After all, the latter is a computational optimization of the former. . Although both lighting models have ready-made code function encapsulation, especially the shaderforge plug-in and the new version of the shadergraph of unity, you can directly drag and drop a few graphical controls to achieve the two lighting. The model effect is simply too much. But after understanding the principle, I won’t feel empty when asked by others.

 

Phong lighting model

Ideally, the light emitted by the light source is reflected by the mirror and is observed in the direction of the reflected light. The observer can receive the most reflected light. Then the angle between the observer and the reflected direction determines how much highlight can be observed. . The larger the angle, the smaller the highlight, and the smaller the angle, the larger the highlight. Another factor that affects the size of the highlight is the smoothness of the surface. The smoother the surface, the stronger the highlight, the rougher the surface, and the weaker the highlight. L represents the light source direction, N represents the vertex normal direction, V represents the observer direction, and R represents the reflected light direction. First, the direction R of the reflected light needs to be calculated. The direction R of the reflected light can be obtained from the incident light direction and the normal vector, R + L = 2dot(N,L)N, and then R = 2dot(N,L)N-L. (As for how to calculate this formula, there are many blogs on CSDN that have notes, which is a simple vector and trigonometric function conversion. If you don’t understand it, you can download it on Baidu or read it directly here )

(Copy another picture by hand)

 

Blinn-Phong lighting model

 

The Phong illumination model can perform the highlight effect very well, but the disadvantage of Blinn-Phong illumination is that it is computationally expensive. Therefore, in 1977, Jim Blinn improved the Phong illumination and called it the Blinn-Phong illumination model.

Blinn-Phong illumination introduces a concept, half-angle vector, represented by H. The half-angle vector is simple to calculate. The half-angle vector can be obtained by normalizing the addition of the light source direction L and the line of sight direction V. Phong lighting compares the angle between the reflection direction R and the line of sight direction V, while Blinn-Phong compares the angle between the half-angle vector H and the normal direction N instead. The calculation complexity of the half-angle vector is much simpler than the calculation of reflected light, so the performance of Blinn-Phong is much higher, and the effect is similar to that of Phong light photography, so the lighting model of the fixed pipeline in OpenGL is the Blinn-Phong lighting model.

The calculation formula of the BlinnPhong illumination model is as follows:

I(spcular) = I * k * pow(max(0,dot(N,H)), gloss), where I is the color vector of the incident light, k is the specular reflection coefficient, and gloss is the degree of smoothness.

==================================================================

Paste the shaderlab code of the two lighting models below

Shader "Custom/Phong" {

Properties{

_Specular("Specular", Color) = (1,1,1,1)

_Diffuse("Diffuse",Color) = (1,1,1,1)

_Gloss("Gloss",Range(1,255)) = 10

}

SubShader{

Pass{

Tags {"LightMode" = "ForwardBase" }

LOD 200



CGPROGRAM

#include "Lighting.cginc"

#pragma vertex vert

#pragma fragment frag



fixed4 _Diffuse;

fixed4 _Specular;

float _Gloss;



struct a2v

{

float4 vertex : POSITION;

float3 normal : NORMAL;

};

struct v2f

{

float4 pos:SV_POSITION;

float3 worldNormal:NORMAL;

float3 worldPos:TEXCOORD1;

};



v2f vert(a2v v)

{

v2f o;

//矩阵变换 获取投影坐标下的顶点

o.pos = mul(UNITY_MATRIX_MVP, v.vertex);

//获取世界坐标下的法线坐标

o.worldNormal = normalize(mul(v.normal, (float3x3)_World2Object));

//o.worldNormal=normalize(mul((float3x3)_Object2World,v.normal));//与上面等价

o.worldPos = mul(_Object2World, v.vertex).xyz;

return o;

}



fixed4 frag(v2f i) :SV_Target

{

//获取环境光

fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*_Diffuse;

//获取灯光方向 并归一化

fixed3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

//归一化世界坐标下的法线

fixed3 worldNormal = normalize(i.worldNormal);

//获取漫反射

fixed3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLight));

//获取反射光的方向 入射光方向为-worldLight,通过reflect函数获取反射光方向

fixed3 reflectDir = normalize(reflect(-worldLight, worldNormal));

//获取点在摄像机的观察位置,并归一化 (相机坐标-像素位置)

fixed3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);

//phong的高光公式

fixed3 specular = _LightColor0.rgb*_Specular.rgb*pow(max(0, dot(reflectDir, viewDir)), _Gloss);

fixed3 color = diffuse + ambient + specular;

return fixed4(color, 1.0);

}

ENDCG

}

}

FallBack "Specular"

}

 

======================================================================

Shader "Custom/Blinn_Phong" {

Properties{

_Specular("Specular",color) = (1,1,1,1)

_Diffuse("Diffuse",color) = (1,1,1,1)

_Gloss("Gloss",Range(1,100)) = 20

}

SubShader{

Pass{

Tags { "RenderType" = "Opaque" }

LOD 200

CGPROGRAM

#include "Lighting.cginc"

#pragma vertex vert

#pragma fragment frag



float3 _Specular;

float3 _Diffuse;

float _Gloss;



struct a2v {

float4 vertex:POSITION;

float3 normal:NORMAL;

};

struct v2f {

float4 pos:SV_POSITION;

float3 worldNormal:NORMAL;

float3 worldPos:TEXCOORD0;

};



v2f vert(a2v a)

{

v2f o;

o.pos = mul(UNITY_MATRIX_MVP, a.vertex);

o.worldNormal = mul(_Object2World, a.normal);

o.worldPos = mul(_Object2World, a.vertex).xyz;

return o;

}



float4 frag(v2f i):SV_Target

{

//获取环境光

float3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz*_Diffuse;

//获取灯光 并且归一化

float3 worldLight = normalize(_WorldSpaceLightPos0.xyz);

//获取法线并归一化

float3 worldNormal = normalize(i.worldNormal);

//获取视线方向(摄像头位置-像素对应位置) 并归一化

float3 viewDir = normalize(_WorldSpaceCameraPos.xyz - i.worldPos.xyz);

//获取漫反射灯光

float3 diffuse = _LightColor0.rgb*_Diffuse.rgb*saturate(dot(worldNormal, worldLight));

//获取半角向量(光线方向+视线方向) 并归一化

float3 halfDir = normalize(worldLight + viewDir);

//高光公式

float3 specular = _LightColor0.rgb*_Specular.rgb*pow(saturate(dot(halfDir, worldNormal)),_Gloss);

float3 color = ambient + diffuse + specular;

return float4(color,1.0);

}

ENDCG

}

}

FallBack "Diffuse"

}

 

=======================================================================================

Some key codes are already commented in the code, so I won’t repeat them too much. And Blinn-Pong introduces a half-angle vector to replace the reflected vector, so the amount of calculation of the shader is much less. The following is a direct summary of the Blinn-Phong shader code.

Blinn-Pong lighting shader

Reference the lighting model "Lighting.cginc"

Define the a2v structure to get the vertices and normals of the model

Define the v2f structure and store the vertex information (SV_POSITION) The world normal and the position of the vertex in the world coordinate

 

Need to get in the vertex function

Projection coordinates of vertices

Vertex world normal

World coordinates of vertices

 

Need to get in the fragment function

Ambient light, you need to multiply the ambient light in the lighting model (UNITY_LIGHTMODEL_AMBIENT.xyz) with Diffuse

Normalized world normal

Normalized light position (_WorldSpaceLightPos0.xyz)

The viewing angle position of the normalized point (_WorldSpaceCameraPos.xyz-worldPos)

漫反射(_LightColor0.rgb*Diffuse.rgb*saturate(dot(worldNormal,lightDir)))

Normalized half-angle vector (viewDir+lightDir)

The final highlight formula LightColor0.rbg*_Specular.rbg*pow(dot(halfDir,worldNormal),_Gloss)

Back to highlight + ambient light + diffuse light

to sum up

        These two lighting models actually have a Chinese name, called Feng Guangzhao model and Brin-Feng Guangzhao model, but after switching to Chinese, it feels a lot of confusing. From the perspective of understanding, the Phong model can draw conclusions more intuitively, and I don’t know how to calculate a half-angle vector of the latter, but the code is much simpler without a dot multiplication operation. The refreshing feeling of posterity.

        I've been lazy for almost a year and only recently had time to suffocate this series of personal understanding. It seems that perseverance is still a word that is not easy to achieve. Although I usually have the habit of taking notes, I feel that after taking notes, I put them there. After a long time, I basically forget everything. It takes a long time to realize it after looking back. This way, writing a blog is a memory of myself. Let's review it, and hope to continue to stick to it. . .

 

Guess you like

Origin blog.csdn.net/ssssssilver/article/details/90232492