수색…


Phong 조명 모델

참고 :이 예는 WIP이며 다이어그램, 이미지, 예제 등으로 업데이트됩니다.

Phong은 무엇입니까?

퐁 (Phong)은 매우 기본적인 조명이지만, 주변, 확산 및 반사 조명의 세 부분으로 구성된 표면의 실제 조명 모델입니다.

주변 조명 :

주변 조명은 이해하고 계산할 수있는 세 부분 중 가장 단순합니다. 주변 조명은 장면을 범람시키는 빛이며 모든 방향으로 대상을 균일하게 밝힙니다.

주변 조명의 두 변수는 주변 광의 강도와 주변 광의 색입니다. 프래그먼트 쉐이더에서 다음은 주변 환경에 대해 작동합니다.

in vec3 objColor;

out vec3 finalColor;

uniform vec3 lightColor;

void main() {
   float ambientStrength = 0.3f;
   vec3 ambient = lightColor * ambientStrength;
   finalColor = ambient * objColor;
}

확산 조명 :

확산 조명은 주변 조명보다 약간 더 복잡합니다. 확산 조명은 지향성 광원으로 광원을 향하는 얼굴이 더 밝게 조명되고 얼굴을 가리키는 얼굴이 빛이 어떻게 반사되어 어둡게 표시됩니다.

참고 : 확산 조명을 사용하려면 각 얼굴에 법선을 사용해야합니다. 여기서는 계산 방법을 보여주지 않습니다. 이를 수행하는 방법을 배우고 싶다면 3D 수학 페이지를 확인하십시오.

컴퓨터 그래픽에서 빛의 반사를 모델링하기 위해 양방향 반사율 분포 함수 (BRDF)가 사용됩니다. BRDF는 나가는 방향을 따라 반사 된 빛과 들어오는 방향에서 들어오는 빛 사이의 관계를 나타내는 함수입니다.

완벽한 확산 표면에는 모든 입 / 출력 방향에 대해 동일한 값을 갖는 BRDF가 있습니다. 이것은 실질적으로 계산을 줄여 주므로 현실 세계에 순수 확산 물질이 없더라도 물리적으로 그럴듯한 확산 표면을 모델링하는 데 일반적으로 사용됩니다. 이 BRDF는 Lambert의 코사인 법칙을 따르기 때문에 Lambertian reflection이라고합니다.

램버트 반사는 종종 확산 반사의 모델로 사용됩니다. 이 기법을 사용하면 3D 메쉬 내의 삼각형과 같은 모든 닫힌 다각형이 렌더링시 모든 방향으로 똑같이 빛을 반사하게됩니다. 확산 계수는 법선 벡터와 빛 벡터 사이의 각도로부터 계산됩니다.

f_Lambertian = max( 0.0, dot( N, L )

여기서 N 은 표면의 법선 벡터이고, L 은 광원쪽으로 향하는 벡터입니다.

작동 원리

일반적으로 2 벡터의 내적 은 두 벡터 사이의 각도 코사인 과 두 벡터의 크기 (길이)를 곱한 것과 같습니다.

dot( A, B ) == length( A ) * length( B ) * cos( angle_A_B ) 

이것은 단위 벡터의 길이가 1이므로 2 개 단위 벡터의 내적은 2 개 개의 벡터들 사이의 각도의 코사인 동일한 것을 따른다.

uA = normalize( A )
uB = normalize( B )
cos( angle_A_B ) == dot( uA, uB )

여기에 이미지 설명을 입력하십시오.

우리가 -90 °와 90 ° 사이의 cos (x) 함수를 살펴보면 0 °의 각도에서 최대 1을 가지며 90 °의 각도에서 0으로 내려갑니다 및 -90 °.

여기에 이미지 설명을 입력하십시오.

이 동작은 리플렉션 모델에 대해 우리가 원하는 것입니다. 표면의 normal vetor와 광원에 대한 방향이 같은 방향 (0 ° 사이의 각도) 일 때 반사의 최대 값을 원한다. 반대로 벡터가 직교 정규화 된 경우 (각도가 90 ° 인 경우) 최소 반사가 필요하며 0 °와 90 °의 두 테두리 사이에서 부드럽고 연속적인 기능 실행이 이루어지기를 원합니다.

여기에 이미지 설명을 입력하십시오.

빛이 정점마다 계산되면 반사는 기본 모서리마다 계산됩니다. 프리미티브들 사이에서 반사는 그것의 barycentric 좌표에 따라 보간됩니다. 구형 표면의 결과 반사를 확인하십시오.

여기에 이미지 설명을 입력하십시오.

좋습니다. 조각 쉐이더로 시작하려면 4 개의 입력이 필요합니다.

  • 정점 법선 (버퍼 내에있어, 정점 속성 포인터에 의해 지정된다)
  • 조각 위치 (버텍스 셰이더에서 frag 셰이더로 출력되어야 함)
  • 광원 위치 (균일)
  • 밝은 색 (균일)
in vec3 normal;
in vec3 fragPos;
    
out vec3 finalColor;
    
uniform vec3 lightColor;
uniform vec3 lightPos;
uniform vec3 objColor;

메인 내부는 우리가 수학을 할 필요가있는 곳입니다. 확산 조명의 전체 개념은 정상 방향과 밝은 방향 사이의 각도를 기반으로합니다. 각도가 클수록 빛이 전혀없는 90 °까지 빛이 적습니다.

빛의 양을 계산하기 전에, 우리는 빛의 방향 벡터가 필요합니다. 이것은 단편 위치에서 빛 위치를 가리키는 벡터를 반환하는 단편 위치에서 빛 위치를 간단히 빼면 검색 할 수 있습니다.

vec3 lightDir = lightPos-fragPos;

또한 normallightDir 벡터를 정규화하여 작업 할 길이가 같아야합니다.

normal  = normalize(normal);
lightDir = normalize(lightDir);

벡터가 생겼으므로 벡터의 차이를 계산할 수 있습니다. 이를 위해 내적 함수를 사용할 것입니다. 기본적으로 이것은 2 개의 벡터를 취하여 형성된 각도의 cos ()을 반환합니다. 이것은 90도에서 0을 생성하고 0도에서 1을 산출하기 때문에 완벽합니다. 결과적으로 빛이 물체를 직접 가리키면 완전히 점등되고 반대의 경우도 마찬가지입니다.

float diff = dot(normal, lightDir);

계산 된 숫자에 대해 할 일이 한 가지 더 있습니다. 항상 긍정적인지 확인해야합니다. 생각해 보면 음수는 문맥 상 이해가되지 않습니다. 그 이유는 빛이 얼굴 뒤에 있다는 뜻이기 때문입니다. if 문을 사용하거나 max() 2 개의 입력을 반환하는 max() 함수를 사용할 수 있습니다.

diff = max(diff, 0.0);

이렇게하면 프래그먼트의 최종 출력 색상을 계산할 준비가되었습니다.

vec3 diffuse = diff * lightColor;
finalColor = diffuse * objColor;

다음과 같이 표시되어야합니다. 여기에 이미지 설명을 입력하십시오.

경면 조명 :

프로그램에서 일하고 나중에 다시 확인하십시오.

결합 된

진행 중이며 나중에 다시 확인하십시오.

아래 코드와 이미지는이 세 가지 조명 개념을 결합한 것입니다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow