ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Shadow Volume (Stencil Shadow) - 원리 (1/2)
    Graphics/Graphics Study 자료 2020. 4. 29. 19:55

    Shadow Volume (Stencil Shadow)

     

    최초작성 : 2020-04-29

    마지막수정 : 2020-04-30

    최재호

     

    목표

    Shadow Volume을 이해하고 구현 합니다. 내용이 많아서 알고리즘/구현 부분으로 분리하여 설명 할 것입니다. 이 장은 Shadow Volume 생성과 Shadow 판정 알고리즘을 다룹니다.

     

    개요

    Shadow Volume 은 이름처럼 Shadow caster와 Light 방향을 기준으로 Shadow volume 을 만들어 Shadow 를 만듭니다. Shadow volume 내부에 있는 경우 Shadow 를 받고, 그렇지 않은 경우 Shadow 를 받지 않습니다. 이러한 처리를 위해서 Stencil buffer를 활용합니다. Shadow Volume 은 기존의 다른 Shadow map 비해서 굉장히 정확한 형태의 Shadow 를 만듭니다. 그리고 Shadow edge는 Hard edge 형태입니다.

     

    Shadow Volume

     

    Shadow Volume을 만드는 Shadow Caster Object의 메시는 반드시 닫혀있어야 합니다. 삼각형들 사이에 틈이 있다면 이 부분 때문에 Shadow 영역에 빛이 새는 현상이 발생합니다.

    빛샘 현상. 원본 오브젝트의 Mesh에 틈이 있으면 Shadow Volume 역시 틈이 생겨서 위와 같이 Shadow 판정에 문제 발생 (GPU Gems : Efficient Shadow Volume Rendering)

     

    Shadow volume을 구현하는 방법은 CPU와 GPU에서 구현하는 방법이 있습니다. CPU 구현방식에는 단점이 있는데, Light의 방향이 변경되면, Shadow Volume을 다시 만들어야 한다는 점입니다. 하지만 GPU 방식에서는 Shadow Volume 생성 연산을 GPU로 옮겨 실시간으로 Shadow Volume을 만들 수 있습니다.

     

    먼저 Shadow Volume 생성 알고리즘은 다음과 같습니다.

     

    1. Shadow Volume 생성을 위한 Vertex 인접 정보 구성
    2. Light 방향을 기준으로 Shadow Volume 생성
      1. Shadow Volume 측면
      2.  Shadow Volume Front Cap
      3.  Shadow Volume Back Cap
    3. 렌더링
      1. Ambient Light로 Object Rendering
      2.  현재 라이트 기준으로 각 오브젝트의 Shadow Volume 을 그림
        1.   Shadow Volume의 Triangle의 감기방향(CW or CCW)에 따라 Stencil buffer 증가 or 감소
      3.  Base Pass - 현재 라이트 기준으로 각 오브젝트 렌더링
        1.  Stencil buffer의 값을 참고하여 오브젝트의 Light 처리 진행
    4. 모든 라이트에 대해서 2)~3) 과정 반복

    위의 과정을 차근차근 알아봅시다.

     

    [1]. Shadow Volume 생성을 위한 Vertex 인접 정보 구성

    [2]. Light 방향을 기준으로 Shadow Volume 생성

    위의 그림에서 처럼 Shadow Volume을 만들려면 오브젝트의 인접정보에서 측면에 해당하는 Edge 들을 검출해내야 합니다.

    오브젝트에 속한 모든 삼각형을 기반으로 아래 정보를 생성합니다.

    1. 삼각형이 가지고 있는 Vertices

    2. 삼각형이 가지고 있는 Edges

     

    이 정보를 기반으로 빛의 방향에 측면에 위치하는 Edge들을 모두 검출합니다. 검출된 Edge들을 Light의 방향으로 확장(Extrude) 시킵니다.

     

    오브젝트의 Vertex 인접 정보들로 Edge를 검출하는 방법은 아래와 같습니다.

    1. 오브젝트의 모든 삼각형들 중 삼각형이 Light 로 or 반대로 향하는 삼각형들의 Edge들을 EdgeSet 컨테이너에 추가합니다.

    2. 만약 이미 추가된 Edge의 경우 제거합니다.

     

    오브젝트에 구멍이 있지 않고 서로 잘 연결되었다면, 아래 그림처럼 파란색 Edge들은 중복되어 나오지 않을 것입니다. 그렇지 않다면 모든 Edge는 두개의 삼각형이 Edge를 공유하고 있기 때문에 모두 제거될 것 입니다.

    파란색 선의 Edge 는 중복되지 않음. (그림에는 사각형 실선이지만 실제로는 삼각형임)

    이렇게 얻어진 Edge를 확장하여 Shadow를 만드는 것은 아래와 같습니다.

    이 상황에서 이런 생각이 들수 있습니다. "위의 그림처럼 추가된 녹색 Vertex는 Light 방향으로 얼마만큼 멀리 떨어진 위치에 만들어야 하나?" Shadow Volume 내부에 있는 오브젝트가 Shadow를 받는 것으로 처리 되어야 하기 때문에 아마 가능하면 이 값은 클수록 좋을 것입니다. 적당히 큰 값을 사용하는 것도 좋지만 Projection Matrix를 조작하여 추가한 녹색 점이 항상 카메라에서 가장 먼 위치에 있도록 합니다.

     

    아래 이미지를 보면, far 를 lim 를 사용해 무한대로 보내어 우측의 Projection Matrix를 얻어냅니다. 이제 위에서 추가한 녹색점의 경우 Infinite Projection Matrix를 사용하여 가장 먼 거리에 위치하도록 합니다. 

    Projection Matrix Tricks Eric Lengyel

     

    무한의 점에 위치시키기 위해서는 Point가 아닌 Vector 형태로 초록색 점을 표현해야 합니다. 그 이유는 아래의 슬라이드 처럼 (x, y, z, 0)의 경우 Infinite Porjection Matrix가 Z값을 1로 만들어 주기 때문입니다.

    Projection Matrix Tricks Eric Lengyel

     

    그래서 새로 추가한 초록색 점은 Vector 형태 (x, y, z 0), 기존 Edge의 Vertex는 (x, y, z, 1)을 사용하여 Shadow Volume의 측면을 구성합니다.

     

    Shadow Volume 의 Front cap과 Back cap은 각각 Shadow volume의 윗면과 아래 면입니다. 이 부분까지 만들어 주면 Shadow Volume은 이름 그대로 하나의 닫힌 공간이 됩니다. Shadow cap 이 없다면, Shadow Volume 내부에서 Shadow를 바라보거나 Light를 바라볼때 문제가 생길 수 있습니다. 이 후 Stencil buffer 사용부분에서 다시 알아보겠습니다. 현재는 Shadow Volume의 Cap을 생성하는 방법만 알아봅시다.

     

    Front cap은 Light를 바라보고 있는 삼각형 면으로 생성하면 되며 Point 형태로 구성합니다. Back cap의 경우는 위에서 Edge 확장(Extrude)하는 경우에 사용했던 방식대로 Vector 형태로 구성하여 Back cap 의 모든 삼각형들이 무한의 점에 존재하도록 합니다.

     

    [3] 렌더링(생성한 Shadow Volume으로 렌더링)

    자, 이제 Shadow Volume을 다 만들었습니다. Shadow Volume을 가지고 Shadow 를 만들어 봅시다.

     

    1. 먼저 Ambient Light 만으로 오브젝트들을 모두 렌더링합니다.

    2. 이제 Shadow Volume 으로 Shadow가 드리우는 위치를 Stencil buffer에 표시합니다.

     1). 1번 과정에서 사용한 렌더타겟을 그대로 유지합니다. (컬러, 깊이 버퍼 유지)

     2). 컬러, 깊이 값을 쓰지 않도록 설정

     3). Cull mode 상관없이 모두 렌더링하도록 설정 (CW, CCW 모두)

     4). 스텐실 버퍼를 활성화 (Depth fail 알고리즘 사용)

      (1). Front Face이고 Depth Test가 실패한 경우 Stencil Value Increment Wrap (앞면방향이면 스텐실 값 증가, 최대값 초과면 최소값으로)

      (2). Back Face익 Depth Test가 실패한 경우 Stencil Value Decrement Wrap (후면방향이면 스텐실 값 감소, 최소값 미만이면 최대값으로)

    3. Lighting Pass

     1). 2번 과정에서 사용한 렌더타겟을 그대로 유지합니다. (컬러, 깊이 버퍼 유지)

     2). 컬러, 깊이 값을 쓰기 허용

     3). Detph는 기존 깊이 버퍼 값과 같은 경우만 렌더링

     4). Stecil 값이 0인 경우만 렌더링 하도록 설정 (Stencil 값이 0이 아니면 Shadow)

    4. 모든 라이트에 대해서 2~3 과정 반복

     

    여기서 Stencil buffer를 사용해서 현재 렌더링 중인 픽셀이 Shadow Volume 내부에 있는가? 여부를 판정하는 부분을 좀 더 자세히 보겠습니다. 이 과정은 GPU에서 Collision Check 하는 알고리즘이라고 생각할 수 있습니다.

    아래 그림이 이 알고리즘을 잘 보여줍니다. 

    2D 로 간략화 된 Stencil operation. 빨간색 선이 Shadow Volume의 Front Face, 파랑색 선이 Shadow Volume의 Back Face

    이 그림의 알고리즘은 위에서 설명한 depth fail 알고리즘이 아닌 기본 알고리즘입니다. Depth Test 성공시에 Stencil buffer의 값을 증가/감소 시킵니다. 하지만 이 알고리즘은 아래와 같은 취약점이 있습니다.

    Near Plane 에 걸려 Shadow Volume 의 Fron face를 렌더링 할 수 없게 된 경우. 아래 이미의 Zero 부분이 Zero가 되지 않고 Shadow 영역으로 판정될 수 있습니다.

     

     

    그래서 아래와 같이 Depth fail 알고리즘을 사용합니다. 아래의 그림에서 빨간 네모 영역에 오브젝트가 존재한다고 하면, Depth Fail 이 되는 경우는 오른쪽 파란색 동그라미 영역에 있는 Shadow Volume Face 일 것입니다. 

    Depth fail 알고리즘

    그래서 눈의 위치에서 가장 먼곳부터 Stencil buffer 값을 변경하므로써, Near plane 에 의해 계산되지 않는 Shadow Volume 정보는 없게 됩니다.

    Depth fail 알고리즘 방식으로 했을때 아래의 파란색 동그라미 부분도 정확히 Shadow 영역으로 판정되는 것을 알수있습니다.

     

    이런 이유로 Light Pass 에서 현재 픽셀에 대응하는 Stencil buffer의 값이 0이 아닌 경우 Shadow Volume 내부라는 것을 알 수 있습니다.

     

    이제까지 Shadow Volume의 생성과 Shadow 판정 알고리즘에 대해서 알아봤습니다.

    설명이 너무 길어져서 2부에서 실제 구현을 따로 다루겠습니다.

     

    추가 내용 (2020.4.30)

    Shadow Volume을 만들때 Convex는 위의 Sphere 예시를 보면 문제가 없는 것 같습니다. 그런데 Concave 같은 경우도 문제가 없나요?

    문제 없이 잘 됩니다. 그런데 Shadow Volume이 여러개 생기는 점, 그리고 Front cap과 Back cap 의 모양이 서로 일치하지 않는 점이 다릅니다. 아래 그림을 보면 Front cap 에서 삼각형들의 실루엣 에지를 사용하여 Front cap이 만들어지고, Edge들을 라이트 방향으로 확장(Extrude)시켜 Shadow volume의 측면을 얻습니다.

    라이트 방향을 향하는 Front cap 기준으로 만든 쉐도우 볼륨 영역 2개

    그리고 아래 그림처럼 Back cap 을 만들기 위해서 라이트 방향으로 바라보지 않는 삼각형들을 라이트 방향으로 확장(Extrude) 시켰는데 Front cap과 모양이 다른 것을 보실 수 있습니다. 하지만 Front cap의 쉐도우볼륨1, 2와 Back cap에서의 2개의 볼륨은 서로 겹치는 부분이 동일하기 때문에 스텐실 연산을 하는데 문제가 없습니다.

    라이트 반대 방향을 향하는 삼각형 기준으로 만든 쉐도우 볼륨 영역, 이제까지의 설명에서는 Shadow Volume 측면을 Front cap 기준으로 만들었기 때문에 Shadow Volume 측면을 다시 만들지는 않음. Back cap을 만들기 위해서 라이트 반대 방향을 향하는 삼각형들의 Vertex 들을 모두 라이트 방향으로 (확장)Extrude 시켜 Back cap으로 사용. Front와 Back cap의 모양이 서로 다르지만 Shadow Volume으로 만들었을 때 서로 겹쳐지는 영역(픽셀들)이 같으므로 Stencil Operation이 잘 작동함.

     

    'Graphics > Graphics Study 자료' 카테고리의 다른 글

    Tiled Forward Rendering  (0) 2020.05.12
    Shadow Volume (Stencil Shadow) - 구현 (2/2)  (0) 2020.05.05
    Exponential Shadow Map(ESM)  (0) 2020.04.23
    Variance Shadow Map(VSM)  (0) 2020.04.16
    Signed Distance Fields  (2) 2020.04.13

    댓글

Designed by Tistory & scahp.