7. Shadow

혀니앤·2022년 10월 19일
0

Shadow

  • 빛이 있을 때의 발생하는 그림자를 계산해야 한다
  • 왜 그림자를 계산해야 할까?
    • 그림자가 없으면 물체가 떠있는지, 바닥에 붙어있는지 모른다 → 사실적이지 않은 느낌
    • 빛이 어디에 있는지 알 수 있게 된다 → Spatial 인지를 도와준다

Shadow 계산을 위해 필요한 요소

  • Light Source
  • Shadow Creators, Casters : 빛을 받아서 그림자를 만들게 되는 물체
  • Shadow Receiver : 실제 그림자를 받는 물체

Shadow Model : Light Type

  • Umbra : 빛을 받지 못하는 부분
  • Directinal Light : 한 점을 기준으로 평행하게 빛이 들어오는 것
  • Point Light : 한 점으로부터 여러 각도로 빛을 내보낸다
    • 그림자가 또렷하게 생긴다
  • Area Light : 한 점이 아닌 면적을 가진다
    • 빛이 area에서 내려오거나 옆으로 가면서 모든 방향에서 빛이 온다
    • PenUmbra : 어느 부분에서는 빛을 받고, 어느 부분에서는 못받으면서 선명하지 않은 애매한 그림자가 생긴다. → 흐릿한 그림자가 생긴다

Shadow Model

  • Soft Shadow : PenUmbra 가 있는 그림자
  • Hard Shadow : PenUmbra 없이 Umbra 만 있어서 선명한 그림자

Shadow Computation

  • 어떤 것을 고려해야 할까?
    • Shadow Castors : 그림자의 기본 모양을 결정한다
    • Shadow Receivers : 받는 물체가 단순한 평면이 아니라 구나 표면이 거친 면일수도 있다
    • Light Sources : 빛에따라 생기는 그림자가 달라진다
  • Straight-forward approach
    • Ray Casting : 카메라에서 빛을 쏴서 물체의 어떤 부분에 닿는지 표시하는 방법

      → Direct 계산엔 좋지만 Indirect에는 안좋다

    • Ray Tracing 을 통해 모든 광원에 대해 Ray를 쏴서 스크린에 도달하는 점들을 표시한다. 빈 공간을 Interpolation 하는 방법

      → 엄청 많은 Ray를 쏴야 한다

      ⇒ 게임은 빨라야하는데 연산이 너무 많다. 더 좋은 방법이 없을까?

Shadow 계산 대안

1) 💡Separate Object

  • 오브젝트를 빛으로부터 오는 공간에 잘게 쪼개서 붙여넣는 방식
  • 가장 빠르게 그릴수 있는 방법이다
  • 단점
    • 빛이 어딨는지에 따라 모양이 다르게 나온다. 하나의 모양으로만 물체를 만들기 어렵다
    • 많은 물체를 빛이 바뀌는 경우에 따라 계속 새로 그려야 한다 (빛이 안 바뀌는 경우에는 좋다)

→ Baking : 미리 화면에 그림자 값을 저장해놓는다. 정적인 경우에 효율적인 방법

  • 언리얼에서는 Static 물체에 대해서는 Baking을 해놓는다
  • 또는 텍스쳐에 그림자 값을 저장해놓기 → 이 경우도 움직이는 케이스 처리 못함

2) 💡 Shadow Volume

  • 광원으로부터 가려지는 물체의, 그림자가 생길 수 있는 영역
  • 캐스터에 의해 생기는 그림자 영역
  • Shadow Volume 안에 있는 영역에는 그림자가 생긴다

  • 일반적으로 좋은 결과를 보여준다. but 계산이 복잡하다

Stencil Buffer

  • 계산을 덜 복잡하게 할 수 없을까?
  • Stencil Buffer를 사용하자!
  • Stencil Buffer : Mask. 0과 1을 적어두면 1에 해당하는 부분만 그릴 수 있다 → Shadow가 생길 부분에 Shadow를 위한 특정한 값을 넣는다

  • 시점에서 특정 지점까지의 직선과 SV 의 교점이 1개면 그림자 안에 있다 (2차원)
  • 시점에서 특정 지점까지의 직선과 frontfacing 평면의 내적이 음이면 빛을 못받으므로 그림자를 넣는다. 양이면 Backfacing이므로 빛을 그린다
  • Stencil Buffer 에 Shadow 그릴 부분을 그린 후, SV에 덧붙여서 그리는 여러 단계를 거쳐야 한다

3) 💡 Shadow Map

  • 빛으로부터 보이지 않는 점을 찾기

  • 내가 그리고자하는 점 P가 광원으로부터 더 가까운 점에서 만난다면 그림자 지점에 있는 것.
  • 특정 픽셀 P로부터 광원까지 중간에 어떤 물체가 있다면 보이지 않는 것
  • Shadow map 에 그림자를 미리 그려놓는다.
  • 프로세스
    • 광원의 입장에서 그림을 한번 그린후 , 픽셀의 depth를 저장한다
    • 시점의 입장에서 다시 그림을 그리고, 이미 그려진 depth와 비교해서 그림자인지를 판단한다
  • 장점 : 쉽고, 빠르다
  • 단점
    • 해상도 문제 : 픽셀단위로 처리하면서, 많은 점이 한 픽셀로 접근하는 경우 그림자가 너무 깨진다.

    • 그림자가 깨끗하게 나타나지 않는다

      → 요즘은 Shadow Volume 방식, Raycasting 방식 을 사용한다


게임 엔진에서의 Shadow Mapping

  • Shadow Technique 기법
    • Shadow Volume : Stencil Shadow를 사용
    • Shadow Texture : 텍스쳐에 그림자 값을 넣어 미리 Baking 된 값을 사용한다
  • 실제 그림자 그리는 방식
    • Modulative : 모든 그림자를 다 어둡게 표현한다
    • Additive Light Masking : 광원에 대해서 그림자를 만들고 섀도우에 입혀지는 색상을 다 더해준다 → 광원마다 계산해야하므로 복잡해진다

Ogre3D 엔진에서의 Shadow

  • 1) Shadow 방법을 설정한다
    • 광원에 따른 SV를 미리 설정한다
  • 2) casting 할 물체와 하지 않을 물체를 지정한다
    • setCastShadows 를 사용해서 설정해준다
  • 3) Recevier를 직접 설정한다
    • setReceiveShadow
  • 따로 Dynamic 한 경우 등을 계산하지는 않는다.

UE4 에서의 Shadow

  • Static Lights
    • static 물체에 대해서만 그림자를 만든다
    • 실시간으로 계산하기엔 계산량이 많아서 미리 계산된 빛, 그림자 값을 사용한다
  • Directional Lights
    • dynamic object가 캐스팅한 빛은 그림자를 많이 만들지 않고, Shadow map을 응용한 방법을 사용한다
  • Per Object Shadow
    • 물체별로 실시간으로 빛을 계산함. Shadow map 문제로 근처에 있는 물체만
  • Movable Lights
    • 모든 물체에 대해 다 계산한다. SV 를 사용한다.
    • map을 쓰면 cast면서 receiver인 물체의 계산은 SV를 쓰는 게 더 좋을수있다
    • Movable 과 Directional 을 함께 쓴다
profile
일단 시작하기

0개의 댓글