본문
(손으로 사진 복사)
Phong 및 Blinn-Phong 조명 모델은 모두 물체에 비추는 빛의 효과를 얻기 위해 사용되며, 물체 성능은 하이라이트 부분을 생성합니다. 두 모델도 매우 유사합니다. 결국 후자는 컴퓨팅 최적화입니다. 전.. 두 조명 모델에는 기성 코드 함수 패키징, 특히 shaderforge 플러그인과 새 버전의 Unity 셰이더 그래프가 있지만 몇 가지 그래픽 컨트롤을 직접 끌어서 놓아 두 가지 조명을 얻을 수 있습니다. 모델 효과는 다음과 같습니다. 단순히 너무 많이. 하지만 원리를 이해 한 후에는 다른 사람의 질문에 공허함을 느끼지 않을 것입니다.
퐁 조명 모델
이상적으로는 광원에서 방출 된 빛이 거울에서 반사되어 반사 된 빛의 방향으로 관찰됩니다. 관찰자는 가장 많이 반사 된 빛을받을 수 있습니다. 관찰자와 반사 된 방향 사이의 각도에 따라 얼마나 많은 하이라이트가 될 수 있는지가 결정됩니다. 관찰되었습니다. 각도가 클수록 하이라이트가 작아지고 각도가 작을수록 하이라이트가 커집니다. 하이라이트의 크기에 영향을 미치는 또 다른 요인은 표면의 부드러움입니다. 표면이 부드러울수록 하이라이트가 강하고 표면이 거칠어지고 하이라이트가 약해집니다. L은 광원 방향, N은 정점 법선 방향, V는 관찰자 방향, R은 반사광 방향을 나타냅니다. 먼저 반사광의 방향 R을 계산해야하며, 반사광의 방향 R은 입사광 방향과 법선 벡터, R + L = 2dot (N, L) N, R = 2dot (N, L) NL. (이 공식을 계산하는 방법은 CSDN에 간단한 벡터 및 삼각 함수 변환 인 메모가있는 블로그가 많이 있습니다. 이해가 안된다면 Baidu에서 다운로드하거나 여기에서 직접 읽을 수 있습니다 . )
(다른 사진을 손으로 복사)
Blinn-Phong 조명 모델
Phong 조명 모델은 하이라이트 효과를 매우 잘 수행 할 수 있지만 Blinn-Phong 조명의 단점은 계산 비용이 많이 든다는 것이므로 1977 년 Jim Blinn은 Phong 조명을 개선하여 Blinn-Phong 조명 모델이라고 불렀습니다.
Blinn-Phong 조명은 H로 표현되는 반각 벡터 개념을 도입합니다. 반각 벡터는 계산이 간단하며, 광원 방향 L과 시선 방향 V를 더하여 정규화하여 반각 벡터를 얻을 수 있습니다. Phong 조명은 반사 방향 R과 시선 방향 V 사이의 각도를 비교하는 반면, Blinn-Phong은 대신 반각 벡터 H와 법선 방향 N 사이의 각도를 비교합니다. 반각 벡터의 계산 복잡도는 반사광 계산보다 훨씬 간단하므로 Blinn-Phong의 성능이 훨씬 높고 효과가 Phong 라이트 사진의 효과와 유사하므로 고정 파이프 라인의 조명 모델 OpenGL에서는 Blinn-Phong 조명 모델입니다.
BlinnPhong 조명 모델의 계산 공식은 다음과 같습니다.
I (spcular) = I * k * pow (max (0, dot (N, H)), gloss), 여기서 I는 입사광의 색 벡터, k는 정반사 계수, 광택의 정도입니다. 부드러움.
================================================ ================
아래 두 조명 모델의 shaderlab 코드를 붙여 넣으세요.
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"
}
================================================ ====================================
일부 키 코드는 이미 코드에 주석 처리되어 있으므로 너무 많이 반복하지 않겠습니다. 그리고 Blinn-Pong은 반사 된 벡터를 대체하기 위해 반각 벡터를 도입하므로 쉐이더의 계산량이 훨씬 적습니다. 다음은 Blinn-Phong 쉐이더 코드를 직접 요약 한 것입니다.
Blinn-Pong 조명 셰이더
조명 모델 "Lighting.cginc"를 참조하십시오.
모델의 정점과 법선을 얻기 위해 a2v 구조를 정의합니다.
v2f 구조를 정의하고 정점 정보 (SV_POSITION)를 저장합니다. 세계 법선과 세계 좌표에서 정점의 위치
정점 함수에 들어가야합니다.
정점의 투영 좌표
정점 세계 법선
정점의 세계 좌표
조각 함수에 들어가야합니다.
주변 광, 조명 모델 (UNITY_LIGHTMODEL_AMBIENT.xyz)의 주변 광과 확산을 곱해야합니다.
정규화 된 세계 정상
정규화 된 조명 위치 (_WorldSpaceLightPos0.xyz)
정규화 된 지점의 시야각 위치 (_WorldSpaceCameraPos.xyz-worldPos)
漫 反射 (_LightColor0.rgb * Diffuse.rgb * saturate (dot (worldNormal, lightDir)))
정규화 된 반각 벡터 (viewDir + lightDir)
최종 하이라이트 공식 LightColor0.rbg * _Specular.rbg * pow (dot (halfDir, worldNormal), _ Gloss)
하이라이트로 돌아 가기 + 주변 광 + 확산 광
요약하자면
이 두 조명 모델은 실제로 Feng Guangzhao 모델과 Brin-Feng Guangzhao 모델이라는 중국 이름을 가지고 있지만 중국어로 전환 한 후에는 많은 혼란을 느낍니다. 이해의 관점에서 Phong 모델은 더 직관적으로 결론을 도출 할 수 있고 후자의 반각 벡터를 계산하는 방법을 모르겠지만 점 곱셈 연산없이 코드가 훨씬 더 간단하다고 느낍니다. 후세의 느낌.
나는 거의 1 년 동안 게으르고 최근에야 이런 개인적인 이해를 질식시킬 시간이 있었는데, 인내는 여전히 깨닫기 쉽지 않은 단어 인 것 같습니다. 평소에는 메모하는 버릇이 있지만 메모를하고 나서 거기에 넣는 것 같은 느낌이 든다. 오랫만에 기본적으로 모든 것을 잊는다. 돌아보고 깨닫는 데는 오랜 시간이 걸린다. 이렇게하면 블로그를 작성한다. 나 자신에 대한 기억입니다. 그것을 복습하고 계속해서 고수하기를 바랍니다. . .