본문 바로가기

DX

조명 기초

조명은 크게 3가지로 나뉜다.

 

 

Directional : 한 쪽 방향으로 쏘는 조명.

 

Point Light : 한 점에서 사방으로 나아가는 조명.

 

Spotlight : 특정 부분만을 비추는 조명.

 

예전에는 컴퓨터가 좋지 않았기 때문에 리얼타임 그래픽스에서는 정확하게 조명을 나타내는 연산이 중요하지 않았다. 그럴듯하게 표현 할 수 있는 최적화 되어 있는 연산, 상황을 구현하는 것이 중요했다.

 

따라서 falloff Start, End 를 사용했다.

Start 거리를 시작으로 이 이상으로 멀어지면 강도 1~0으로 줄어들며 해당 픽셀을 어둡게 만들었다. 따라서 멀리 있는 조명은 애초에 강도 0이니 연산에서 빼버리기 때문에 최적화 할 수 있었다.

 

 

 

 

3가지 조명의 기초 연산 식

 

Directional : 기초 블린 퐁을 위한 계산

Point Light : 조명의 위치와 정점의 위치, 거리(d 강도) 를 기반으로 빛의 방향과 세기를 결정 후 퐁 쉐이딩

Spot Light : 포인트 조명에서 Spot 조명은 방향이 결정되어 있기 때문에 구하려는 정점의 위치와 조명 방향의 내적을 추가하여 바로 구할 수 있다.

vec3 ComputeDirectionalLight(Light L, Material mat, vec3 normal, vec3 toEye) {
    vec3 lightVec = -L.direction;

    float ndotl = glm::max(dot(lightVec, normal), 0.0f);
    vec3 lightStrength = L.strength * ndotl;

    // Luna DX12 책에서는 Specular 계산에도
    // Lambert's law가 적용된 lightStrength를 사용합니다.
    return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}

// 쉐이더에서 많이 사용되는 함수입니다. HLSL에는 내장되어 있습니다.
// https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-saturate
float Saturate(float x) { return glm::max(0.0f, glm::min(1.0f, x)); }

float CalcAttenuation(float d, float falloffStart, float falloffEnd) {
    // Linear falloff
    return Saturate((falloffEnd - d) / (falloffEnd - falloffStart));
}

vec3 ComputePointLight(Light L, Material mat, vec3 pos, vec3 normal,
                       vec3 toEye) {
    vec3 lightVec = L.position - pos;

    // 쉐이딩할 지점부터 조명까지의 거리 계산
    float d = length(lightVec);

    // 너무 멀면 조명이 적용되지 않음
    if (d > L.fallOffEnd)
        return vec3(0.0f);

    lightVec /= d;

    float ndotl = glm::max(dot(lightVec, normal), 0.0f);
    vec3 lightStrength = L.strength * ndotl;

    float att = CalcAttenuation(d, L.fallOffStart, L.fallOffEnd);
    lightStrength *= att;

    return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}



vec3 ComputeSpotLight(Light L, Material mat, vec3 pos, vec3 normal,
                      vec3 toEye) {
    vec3 lightVec = L.position - pos;

    // 쉐이딩할 지점부터 조명까지의 거리 계산
    float d = length(lightVec);

    // 너무 멀면 조명이 적용되지 않음
    if (d > L.fallOffEnd)
        return vec3(0.0f);

    lightVec /= d;

    float ndotl = glm::max(dot(lightVec, normal), 0.0f);
    vec3 lightStrength = L.strength * ndotl;

    float att = CalcAttenuation(d, L.fallOffStart, L.fallOffEnd);
    lightStrength *= att;

/// 추가!!!!
    float spotFactor =
        glm::pow(glm::max(dot(-lightVec, L.direction), 0.0f), L.spotPower);
    lightStrength *= spotFactor;

    return BlinnPhong(lightStrength, lightVec, normal, toEye, mat);
}

 

스포트라이트는 방향이 있고 실제 구할 위치점과 얼마나 각이 졌는지에 따라 빛의 세기가 달라지도록 만든다.

 

 

Point Light

 

 

Spot Light

 

 

 

 

 

 

 

 

 

 

 

 

 

'DX' 카테고리의 다른 글

역행렬과 컴퓨터 그래픽스 (짧)  (0) 2025.05.11
Orthogonal  (0) 2025.05.11
쉐이딩  (0) 2025.05.01
원근 투영 실습  (0) 2025.04.30
뒷면 제거  (0) 2025.04.30