본문 바로가기
Graphic/Computer Graphics

[Graphics] Phong Reflection Model(Ambient / Diffuse / Specular) 이해하기

by 여기는 정글 2025. 2. 4.

안녕하세요.

정글러입니다.

언리얼엔진에서 블루프린트를 활용하여 쉐이더를 만든 적이 있죠.

그 원리를 이해하기 위해선 Phong Reflection Model을 이해해야 합니다.

 

Ambient

사실적인 느낌을 내는 데에 그렇게 중요하진 않습니다.

ambient는 물체가 내는 색깔이라고 볼 수 있습니다.

// Ambient 성분

result.ambient = ka * ambientLight;

Diffuse

Ambient에 diffuse를 추가하면 입체감이 살아나게 됩니다.

diffuse는 한 점에서 받는 빛의 강도를 계산합니다.

이때 벡터n(한 점)과 벡터l(점에서 빛으로 향하는 벡터)는 각도가 커지면 커질 수록 빛을 덜 받습니다.

조명의 방향에 따라서 강하게 보여줄지, 약하게 보여줄지 정하는 것입니다.

// Diffuse 성분

result.diffuse = calculateDiffuse(normal, lightDir);

float calculateDiffuse(const glm::vec3& normal, const glm::vec3& lightDir) {
        // 법선 벡터와 빛의 방향 벡터를 정규화
        glm::vec3 N = glm::normalize(normal);
        glm::vec3 L = glm::normalize(lightDir);
        
        // diffuse 계산: max(0, N · L)
        float NdotL = glm::max(0.0f, glm::dot(N, L));
        
        return kd * NdotL;

 

Specular

빛이 강하게 모여있는 것, 반짝거리는 느낌을 살릴 때 사용합니다.

예전에 셰이더 구조에서 살펴본 바가 있습니다.

 

[Unreal Engine] 쉐이더 구조 및 언리얼 렌더링 파이프라인 이해하기

안녕하세요. 정글러입니다. 1. Shader먼저 쉐이더의 구조와 PBR, 텍스쳐의 상호작용 등을 살펴보겠습니다.쉐이더의 기본 구조와 흐름은 다음과 같이 이루어져 있습니다.BufferVertex ShaderRasterizerPixel

storytech.tistory.com

이 그림 기억나시나요?

앞선 Diffuse는 표면이 울퉁불퉁(종이, 나무)한 반면에, Specular는 매끈한 표면(금속, 거울)인 것이지요.

// Specular 성분

result.specular = calculateSpecular(normal, lightDir, viewDir);

   float calculateSpecular(const glm::vec3& normal, const glm::vec3& lightDir, const glm::vec3& viewDir) {
        // 모든 벡터를 정규화
        glm::vec3 N = glm::normalize(normal);
        glm::vec3 L = glm::normalize(lightDir);
        glm::vec3 V = glm::normalize(viewDir);
        
        // 반사 벡터 계산 R = 2(N · L)N - L
        float NdotL = glm::dot(N, L);
        glm::vec3 R = glm::normalize(2.0f * NdotL * N - L);
        
        // specular 계산: max(0, V · R)^shininess
        float VdotR = glm::max(0.0f, glm::dot(V, R));
        float specular = glm::pow(VdotR, shininess);
        
        return ks * specular;
    }

 

 

// 전체 조명 계산

result.total = result.ambient + result.diffuse + result.specular; return result;

 

블루프린트로 해볼 때는 원리를 이해하지 못하고 셰이더 값을 조절 했었는데,

다음번 셰이더를 할 때는 더 잘 만들 수 있을 것 같습니다! (바람)

 

감사합니다.