08. Shadow

DV·2024년 5월 19일

DirectX_3D

목록 보기
9/13

📒Shadow


📌개념적 흐름

  1. Depth Map 생성
    • 광원 기준 샷 따로 찍음 : 깊이 저장
  2. Depth Map 투영
    • 메인카메라가 보는 월드를 다시 전역광원 깊이샷에 투영시켜봄
    • 광원에서 볼 수 있는지, 즉 그림자지는 부분인지 아닌지 판단

(복습) scene 찍기

  • tick: shader domain의 obj들을 따로 모아둠
  • render: 모은 그룹의 각 obj마다 render 호출
  • shader:
    • 세팅한 RT & DST에다가,
    • 각 VS에서 들어온 Vtx의 local 값을 ➡️ WVP 행렬 연산해 Screen 좌표로 보내 얻은
    • 본인의 위치에 값 연산해 그림
    • 그룹의 모든 obj마다 반복
  • 해당 shader domain 그룹의 texture 완성!
    • 모든 그룹마다 위 과정 수행

: 즉, 그림자를 생성하는 obj를 모아 shader depth map을 그리는 render 호출하면, 각 obj마다 shadow depth shader를 통해 light에서 바라보는 모습을 그려, shadow depth texture를 완성함

📌Setting

[ShadowDepth MRT]

  • ShadowDepth Tex (RT)
    • Texture 해상도:
      • 화면에 그리는 용도가 아닌 Shader용으로 제작하기 때문에 화면크기와 달라도 됨
      • Texture의 최대크기: 8192
    • Directinal Light: 월드 전체를 그려야 하므로 해상도가 커야 함
    • Point Light: 정해진 range 안의 물체만 그리므로 작아도 괜찮음(512~1024)
  • DepthStencil Tex
    • RT와 같은 해상도의 DS용 Tex 따로 생성

📌Shadow Drawing

  1. Viewport 설정

    • Viewport 크기와 Render Target 크기:

      • 처음부터 RT 크기가 아닌 Viewport 설정(크기)에 맞춰서 그려짐
      • 즉, Viewport와 Render Target의 크기가 다를 때 늘어나거나 줄어드는 개념이 아니라
      • RenderTarget에서 Viewport만큼의 크기에 렌더링되는 것
    • Viewport 설정 단계: Rasterizer 이전

      • Viewport는 Rasterizer 단계에 영향을 줌
      • MRT가 Viewport Size를 들고 있어야 함
    • Viewport의 크기가 제대로 세팅되지 않는다면

      • Rasterizer: Viewport만큼의 크기에 호출시켜줌
      • RT Copy: 전체 Render Target 영역을 대상으로 호출됨
  2. ShadowDepth rendering
    : 광원 시점에서 물체의 깊이 그림

    • 광원 시점 View & Proj 행렬을 통해 물체의 깊이 그림

      • 카메라 컴포넌트에서 구현해뒀으므로
      • Light3D에서 CamObj를 들고 행렬 계산용으로만 사용하도록 설계
    • Proj Type

      • Directional Light: 직교투영
        • DirLight는 태양광이므로 모두 같은 방향을 가져야 함
        • 태양은 멀리 떨어져 있으므로 월드값 즉, 근소한 값의 차이에 차이 발생 않음
      • Point Light: 원근투영

    Shadow depth texture의 각 Pixel

    • position : Light가 바라보는 관점 기준
    • 기록정보 :
      • r : depth, Light로부터 떨어진 정도 기록
  3. Shadow Shading

    • Light가 추가적으로 필요한 정보 (바인딩)
      • Shadow Depth Tex
      • Light ViewProj mat
    • 그림자 지는 부분 확인
      : Pixel Shader에서 현재 픽셀의 위치를 Shadow Depth Tex로 투영해 그림자 지는 부분인지 판단
      • 변환행렬: pixel 위치 * View Inv mat * Light ViewProj mat
    • 판단
      • Shadow Depth Tex로 투영해 추출한 값(Depth)이 예상한 값보다 더 앞이라면, 즉 추출값이 계산값보다 더 작다면
      • 앞에 빛을 가리는 물체가 있었음
      • 즉 그림자지는 부분
    • 보정값(Magic Number): 실수계산이라 작은 오차가 존재할 수 있으므로 값 보정해서 인정

📌Alising

: Directional Light의 경우 깨짐현상 발생

  • 이유
    • 이유1: Directional Light가 멀리서 찍기 때문에, 확대했을 때 깨짐
    • 이유2: deferred라서 Anti-Alising 처리가 안됨
  • 해결: 별도의 단계
    • 그림자만 처리하는 단계 분리해야 함
    • 이후 blur 등으로 직접 처리

📌광원의 범위를 벗어나는 경우

: 광원의 범위를 벗어나서 그림자가 갑자기 사라지면 어색해 보임

  • 방법1: 그림자 그리지 않기
  • 방법2: follow (dynamic의 경우)
    • dynamic light는 main cam을 따라다님
  • 방법3: 광원 반복배치 (static의 경우)
    • 광원을 반복적으로 배치해서 연속적으로 그림자 그려줌

📌애니메이션 그림자

  • 광원은 TPose를 받지만 애니메이션을 플레이하는 경우
  • 그림자를 찍을 때 Skinning작업을 해줘야 함

📒 Point Light Shadow


: Dir Light와는 달리 그림자가 육면체형태로 6번 판정 및 렌더링 돌아야 함

  • 최적화: Geometry 셰이더
    - 하나의 시점에서 여러방향 뽑을 수 있음

📒 최적화


📌Static Object vs Dynamic Object

[Object Type]

  • static: 처음 1회 그림자 그려 사용
  • dynamic: 매 틱 그림자 그려 사용

[Object Shadow Option]

  • enable: 그림자 생기는 오브젝트
  • disable: 그림자 생기지 않는 오브젝트

[Light Shadow Option]

  • enable: 그림자 만드는 빛
  • disable: 그림자 만들지 않는 빛

📌최적화

: 그림자를 그리기 위해선 결국 렌더링 횟수가 증가하니 프레임드랍 발생함

  • 움직이지 않는 것, static한 물체들은 미리 (한 번) 그려놓고 다시 그리지 않음
  • 변형이 있는 물체, dynamic한 물체들만 계속 다시 그림

0개의 댓글