수업


✅ 주제

  • 본 강의의 주제는 Emissive Light(자가 발광 조명)을 활용하여
    물체의 외곽선을 강조하는 림 라이트(Rim Light) 효과를 구현하는 것이다.
  • 외부 광원(LightDir, LightColor) 없이, 카메라 방향과 Normal의 각도 차만을 이용하여 윤곽선 강조를 수행한다.

📘 개념

🔹 Emissive 조명이란?

  • Emissive는 물체 자체가 빛을 내는 것처럼 보이도록 하는 조명 기법이다.
  • 일반적으로 사용되는 조명(Diffuse, Specular)은 외부 광원의 방향과 색상에 따라 조명이 적용되지만,
    Emissive는 광원 없이도 표현 가능하다.
  • 이번 강의에서는 이 Emissive를 외곽선을 강조하는 Rim Light 방식으로 구현한다.

🔹 작동 원리

  1. Eye 벡터(E) = 픽셀 위치에서 카메라 위치를 향하는 벡터
  2. Normal 벡터(N) = 표면 법선 방향
  3. dot(E, N)은 정면일수록 1, 수직일수록 0
  4. 외곽은 수직인 곳이므로, 1 - dot(E, N)을 사용해 외곽 정도를 계산
  5. 그 결과를 smoothstep()으로 보정하여 부드럽게 외곽 강조값 생성
  6. 해당 값을 MaterialEmissive에 곱해 최종 색상 출력

🧾 용어 정리

용어설명
Emissive Light자가 발광 조명. 물체가 자체적으로 발광하는 시각적 효과
Rim Light림 라이트. 물체의 가장자리(윤곽선)에 강조를 주는 기법
Eye 벡터 (E)픽셀 → 카메라로 향하는 방향 벡터
dot()두 벡터의 방향 각도 계산. 1이면 일치, 0이면 수직
saturate()0~1로 clamp. 음수나 1 초과 제거
smoothstep(a,b,x)a~b 범위의 x를 부드럽게 보간
pow(x,n)값의 강조 혹은 경계 영역 조절

🧠 코드 분석


📄 HLSL 셰이더: Lighting_Emissive.fx

🔹 변수 선언

#include "00. Global.fx"

float4 MaterialEmissive;
  • 외부 광원 관련 변수(LightDir, LightDiffuse)는 사용하지 않으므로 제거
  • MaterialEmissive만 남김: 물체의 발광 색상을 결정

🔹 정점 셰이더 (VS)

MeshOutput VS(VertexTextureNormal input)
{
    MeshOutput output;
    output.position = mul(input.position, W);             // 월드 좌표계로 변환
    output.worldPosition = output.position;               // 카메라 위치 연산용
    output.position = mul(output.position, VP);           // 클립 좌표로 변환
    output.uv = input.uv;
    output.normal = mul(input.normal, (float3x3)W);        // 회전만 반영된 노멀
    return output;
}
  • worldPosition: Eye 벡터 계산을 위해 필요
  • 노멀은 월드 기준에서 회전만 적용

🔹 픽셀 셰이더 (PS)

float4 PS(MeshOutput input) : SV_TARGET
{
    float3 cameraPosition = -V._41_42_43;
    float3 E = normalize(cameraPosition - input.worldPosition);  // 카메라 방향 벡터

    float value = saturate(dot(E, input.normal));  // 정면일수록 1, 수직일수록 0
    float emissive = 1.0f - value;                 // 수직일수록 강조

    emissive = smoothstep(0.0f, 1.0f, emissive);   // 부드러운 그라데이션 적용
    emissive = pow(emissive, 2);                   // 강조 영역 좁힘

    float4 color = MaterialEmissive * emissive;    // 색상 = 강조값 × 재질색
    return color;
}
  • dot(E, N) → 중심부일수록 1, 외곽일수록 0
  • 1 - value → 외곽일수록 값이 커짐
  • smoothstep + pow 조합으로 자연스럽고 날카로운 외곽선 생성
  • 광원 정보 없이 카메라 시점에 따라 강조

📄 technique 정의

technique11 T0
{
    PASS_VP(P0, VS, PS)
};
  • 단일 패스 구성: 정점 셰이더 → 픽셀 셰이더

💻 C++: EmissiveDemo.cpp

🔹 Init()

_shader = make_shared<Shader>(L"12. Lighting_Emissive.fx");
  • Emissive 전용 셰이더 로드
_obj->GetMeshRenderer()->SetShader(_shader);
// Sphere 메시, 텍스처 설정 생략
_obj2->GetMeshRenderer()->SetShader(_shader);
// Cube 메시, 텍스처 설정 생략
  • 각 오브젝트에 Emissive 셰이더 설정

🔹 Update()

Vec4 materialEmissive(1.f, 0.f, 0.f, 1.f); // 빨강
_shader->GetVector("MaterialEmissive")->SetFloatVector((float*)&materialEmissive);
_obj->Update();

Vec4 materialEmissive2(0.f, 1.f, 0.f, 1.f); // 초록
_shader->GetVector("MaterialEmissive")->SetFloatVector((float*)&materialEmissive2);
_obj2->Update();
  • 각 물체마다 서로 다른 발광 색상 설정 가능

📊 실험

조건결과
Emissive 적용외곽선 강조 발광 효과 확인
pow(emissive, 2) 적용외곽선이 더 얇고 날카롭게 표현됨
Sphere 오브젝트곡면이 많아 외곽 강조 효과 뚜렷
Cube 오브젝트평면 노멀이 균일해 외곽선 표현이 덜 뚜렷

🔍 수식 분석

  • 기존 조명: dot(N, L) → 정면일수록 밝게
  • Emissive 림라이트: dot(N, E)정면일수록 어둡게, 수직일수록 밝게
float value = saturate(dot(E, N)); // 정면 = 1
float emissive = 1.0f - value;     // 반전 → 외곽 강조
  • smoothstep는 외곽의 색상 변화 경계를 부드럽게
  • pow()강조 영역 축소 → 더 날카롭고 선명한 외곽선 표현 가능

✅ 핵심

  • Emissive는 조명을 받지 않아도 물체가 자체 발광하는 효과를 만든다.
  • 카메라 방향(Eye)과 Normal이 수직일수록 외곽선으로 간주하고 강조한다.
  • 핵심 수식은 1 - dot(E, N)이며, 이를 smoothstep()pow()로 보정해 효과를 조절한다.
  • 광원이 없는 상황에서도 림 라이트 기반 외곽선 강조 효과를 매우 간단하게 구현할 수 있다.
  • 다양한 색상 적용, 강조 범위 조절, UI 연동 등으로 확장 가능하다.

profile
李家네_공부방

0개의 댓글