수업


✅ 주제

  • DirectX11 기반 실시간 렌더링에서 Ambient Light(환경광)를 구현하고, Shader와 재질(Material)의 상호작용을 통해 물체에 일정한 조도를 부여하는 기초 조명 시스템을 구현하는 방법을 학습한다.

✅ 개념

  • 우리가 물체를 볼 수 있는 이유는 빛이 물체에 닿고 반사되어 눈으로 들어오기 때문이다.
  • 하지만 실제 조명은 수많은 난반사와 굴절이 얽혀 있으므로, 이걸 실시간으로 GPU에서 처리하는 건 불가능하다.
  • 따라서 현실의 조명을 흉내 내는 단순화된 조명 모델을 사용한다.
  • 이 중 Ambient Light는 물체에 광원이 직접 닿지 않아도 일정한 조도로 보이게 해주는 기본 조명이다.
  • Ambient는 방향성이 없고, 항상 일정한 색상과 밝기를 가지며, 그림자나 하이라이트 없이 전반적인 밝기 효과만 부여한다.
  • Diffuse, Specular, Emissive 조명과 함께 최종적으로 조명 시스템을 구성하게 된다.

✅ 용어정리

용어의미
Ambient Light환경광. 광원에서 직접 닿지 않은 빛들이 반사되어 퍼지는 간접광
LightAmbient광원이 가지고 있는 Ambient 색상 (조명 색상)
MaterialAmbient물체가 Ambient 조명에 반응하는 비율 또는 재질 특성
ShaderGPU에서 실행되는 프로그램. 조명, 변환, 색상 결정 등을 담당
Vertex Shader (VS)정점 위치 계산 (월드 → VP 변환)
Pixel Shader (PS)픽셀별로 최종 색상 계산 (조명, 텍스처 연산)
Sampling텍스처 좌표 기반으로 픽셀 색상 추출
Multiplicative Lighting조명 색 × 재질 색으로 조도 계산하는 방식

✅ 코드 분석

🔹 Shader 파일: 09. Lighting_Ambient.fx

#include "00. Global.fx"

float4 LightAmbient;       // 광원의 환경광 색상
float4 MaterialAmbient;    // 재질의 환경광 반응 정도
  • 조명과 재질 각각의 색상이 float4로 선언되어 있고, PS에서 곱해진다.

VertexOutput VS(VertexTextureNormal input)
{
    VertexOutput output;
    output.position = mul(input.position, W);   // 월드 변환
    output.position = mul(output.position, VP); // 뷰-프로젝션 변환

    output.uv = input.uv;
    output.normal = mul(input.normal, (float3x3)W); // 회전 성분만 포함

    return output;
}
  • 정점 좌표를 월드-뷰-프로젝션으로 변환하여 화면상 위치로 설정
  • 노멀은 회전만 반영하여 조명 방향 계산에 사용할 준비

Texture2D Texture0;

float4 PS(VertexOutput input) : SV_TARGET
{
    float4 color = LightAmbient * MaterialAmbient;
    return color;
}
  • 픽셀 셰이더에서 조명 색과 재질 색을 곱하여 조도 계산
  • 지금은 텍스처 적용 없이 순수 조명 색상만 화면에 출력

🔹 AmbientDemo.cpp

_shader = make_shared<Shader>(L"09. Lighting_Ambient.fx");
  • Ambient 조명 전용 쉐이더 파일을 불러온다.

_camera = make_shared<GameObject>();
_camera->GetOrAddTransform()->SetPosition(Vec3{ 0.f, 0.f, -10.f });
  • 카메라를 뒤쪽으로 배치하여, 두 오브젝트를 관찰하기 쉽게 만든다.

Sphere, Cube 오브젝트 생성

_obj = make_shared<GameObject>();
_obj->AddComponent(make_shared<MeshRenderer>());
_obj->GetMeshRenderer()->SetShader(_shader);
_obj->GetMeshRenderer()->SetMesh(RESOURCES->Get<Mesh>(L"Sphere"));
_obj->GetMeshRenderer()->SetTexture(RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg"));
_obj2 = make_shared<GameObject>();
_obj2->GetOrAddTransform()->SetPosition(Vec3{ 0.5f, 0.f, 2.f });
_obj2->AddComponent(make_shared<MeshRenderer>());
_obj2->GetMeshRenderer()->SetShader(_shader);
_obj2->GetMeshRenderer()->SetMesh(RESOURCES->Get<Mesh>(L"Cube"));
_obj2->GetMeshRenderer()->SetTexture(RESOURCES->Load<Texture>(L"Veigar", L"..\\Resources\\Textures\\veigar.jpg"));
  • Sphere와 Cube 두 개의 오브젝트를 생성하고, 동일한 텍스처와 쉐이더를 사용

🔹 Update 함수: 조명/재질 값 전달

Vec4 lightAmbient{ 0.5f, 0.f, 0.f, 1.f };
_shader->GetVector("LightAmbient")->SetFloatVector((float*)&lightAmbient);

Vec4 materialAmbient(1.f);
_shader->GetVector("MaterialAmbient")->SetFloatVector((float*)&materialAmbient);
_obj->Update();
_obj2->Update();
  • 붉은 Ambient 조명을 설정하고, 두 오브젝트가 모두 그 영향을 100% 받도록 materialAmbient를 (1,1,1,1)로 설정
  • 결국 두 물체는 붉게 표현됨

🔹 샘플링과 혼합 테스트 (Shader 수정)

float4 color = LightAmbient * MaterialAmbient;
return Texture0.Sample(LinearSampler, input.uv) * color;
  • 텍스처 색상과 Ambient 조명을 곱하여 더 현실적인 표현 가능
  • 붉은 빛만 반영되면 텍스처의 붉은 부분은 밝고, 다른 색은 어둡게 표현됨

✅ 핵심

  1. Ambient 조명은 광원이 명확하지 않아도 은은한 조도를 제공하는 간접광의 개념이다.
  2. 픽셀 쉐이더에서 LightAmbient × MaterialAmbient만으로 간단하게 구현할 수 있다.
  3. 이후에 Diffuse, Specular, Emissive 조명을 순차적으로 결합해가며 완전한 조명 시스템을 구현할 수 있다.
  4. 텍스처 샘플링과 곱해줄 경우 실제 텍스처의 색상에 조명 효과가 반영되어 더 자연스러운 시각 효과를 만들 수 있다.
  5. 재질(material)마다 반응 정도를 다르게 하여, 광원에 따라 다른 물체는 다르게 보이도록 구현 가능하다.
  6. Shader 공식은 고정된 정답이 없고, 실험과 시각적 판단에 따라 구성될 수 있다.

profile
李家네_공부방

0개의 댓글