트위터위젯,PSN카드위젯



ShadowMap 게임 플밍

결국 볼륨섀도우 축퇴사각형(degenerate quad) 작성 알고리즘의 문턱에서 포기를 하고
(스킨메쉬에 적용시킬려니 스키닝 연산을 줄일 방도가 없었다...
메쉬를 별도의 정점버퍼에 복사해서 CPU상에서 프레임마다 한번씩 일괄적으로 스키닝 연산 후
Lock-Unlock 한방에 메쉬정점을 교체했는데, 락-언락보다
정점 갯수 만큼의 행렬 연산이 너무 시간이 많이 걸려서-어떻게 연산을 최적화 해야하는지도 잘 모르고-
CPU상에서의 처리는 결국 포기 ㅠ.ㅠ)
섀도우 맵으로 넘어왔다.

섀도우맵을 읽는 UV좌표 설정부분에서 살짝 막히긴 했지만,

결국 어제 렌더까지는 성공시켰다.

우훗! 좋은 계단!

...

뭐 섀도우맵의 가장 큰 단점이 앨리어싱이란건 익히 알고 있었으나
과연 ㄷㄷㄷ

그에따라 섀도우맵의 앨리어싱을 극복하고자 수많은 알고리즘들이 개발되었으나
아직 현재진행형이라 할만하다.

섀도우맵에 쓰이는 안티앨리어싱 기법은 크게 두 분류로 나누어 볼 수가 있겠다.


첫번째, 라이트 프러스텀을 조작하여 최대한 효율적인 섀도우맵을 획득하는 방법.

두번째. 섀도우맵으로부터 값을읽어서 그림자를 색칠할때 주변값들과 보정시키는 필터링.


전처리, 후처리라 할만하도다.

먼저 내용 이해가 쉬웠던 후처리부터 들어가자면,
ShaderX2 에 소개되어 있는 PCF(Percentage Closer Filtering),
nVIDIA 에 공개된 VSM(Variance Shadow Map : 편차 그림자 지도...)이 있겠다.
(사실 이거밖에 모름 ㅇ.ㅇ;; )
VSM 문서에는 DSM(Deep Shadow Map)이란놈도 소개되어 있는데,
문서 찾아봤다가 이건뭐.. 그냥 잊어버리는게 정신건강에 좋을것 같다.

PCF에 쌍선형(Bilinear)필터를 적용시키면 꽤 좋은 품질의 안티앨리어싱을 걸 수 있는데,
VSM문서에서는... 비싸댄다 -_-;
그래서 일단 후처리는 VSM만 믿고 가볼까 한다.

VSM은
                                    [그림출처 : nVIDIA VSM문서. 좌측이 분포함수, 우측이 누적분포함수]

누적분포함수를 응용하여 주변색에 필터링을 거는 방식으로,
더이상의 자세한 설명은 엔비댜 문서를 참고하시고잉,
요걸 최대한 간결하게 후처리용으로 써볼까 한다.

이제 최대의 문제는 전처리.
아무것도 하지않고 그냥 광원시점의 거리값을 그대로 텍스쳐에 보존한게 SSM(Standard Shadow Map)이고
현재 내가 구현한게 요놈. 결과는 뭐 보시는대로 -_-

이 다음부터는 PSSM문서를 보면 차이가 느껴진다.
                 [그림출처 : PSSM문서. 요것만 보면 PSSM이 킹왕짱이다(뭐 실제로도 따지고 보면 그렇다 -_-; ) ]

PSM은 광원시점 절두체(라이트 프러스텀...이라고 하자)를 변형하여
섀도우 맵의 효율을 높이는 방식인데, 이후에 등장한 LiSPSM, TSM역시 기본 이념은 동일하다.
단지 라이트 프러스텀을 어떻게 변형해서 최대의 효율을 이끌어내는지의 차이가 존재한다.

이제 막 SSM을 구현했을뿐이기에,
아직 PSM의 기본개념조차 파악 못한 꼬꼬마라,
더이상의 설명은 불가능하리라 싶다.

LiSPSM은 이름처럼, PSM의 개선판이고,(도대체 라이트 공간이 뭐여? -_-;)
TSM은 사다리꼴 형태로 프러스텀을 변형시킨다... 정도만 알고있다.
TSM은 프러스텀과 상관없을수도 있다.(내가 잘 모르는거지뭐.)

그리고 PSSM... 구간별로 나눠서 처리를 하고...
CSM이란것도 있던데. 에휴.

공부해나가면서 알게 되면
기록이나 끄적끄적 남겨야겄다.


-----------------------------2008년 7월 8일 추가분-------------------------------------------------------

PSM(Perspective Shadow Map)


PSM은 일단 카메라 시점을 기준으로 월드-뷰-프로젝션 변환을 일단 한 상태에서 시작한다.
프로젝션 변환을 한 상태이기때문에
카메라에 가까운 부분은 크게, 먼 부분은 작게 쪼그라 든 상태이다.
이걸 포스트-퍼스펙티브(post-perspective)상태라 하는데,
월드 공간자체가 뒤가 좁게 쪼그라 든 상태라,
다시말하면 뷰프러스텀은 정육면체(실은 z축 길이는 0~1까지라 절반밖에 안되지만...)로
변형된 퍼스펙티브 공간이다.

         [ 그림출처 : PSM문서. 그냥 월드-뷰-프로젝션(일명WVP)변환을 했을 뿐이다. 뭘 거창한 이름을 붙이고 그래... ]

여기서, 디렉셔널 라이트의 경우엔 프로젝션변환의 영향을 받지 않는다고 나와있어서
(이 부분은 아직 이해가 덜 됐다. 다를수도 있다)
정육면체화 된 뷰프러스텀을 최대한 포함하는 라이트 프러스텀을 적절하게 계산해서
섀도우 맵을 찍는다.

단점은, 프로젝션 변환 후의 공간엔 문제가 많아서
(시점에 딱 맞게 바꿔주는 건데 공간만 바꾸고 다른 지점에서 바라보니까 당연히..)
라이트가 시점과 비슷한 방향일 경우, 시점보다 앞에 위치한 물체가
뒤쪽에 큼지막하게 자리잡는 경우가 생기거나
각도에 따라서 전혀 혜택을 못 보는경우(앨리어싱이 전혀 나아지지 않는),
먼 곳의 오브젝트에는 너무 적은 픽셀을 할당하기에
멀리있는 오브젝트의 앨리어싱은 가히 살인적이라는점
(어차피 멀리있는 물체는 작으니까 상관없지 않겠냐고 생각하겠지만,
큰 건물이라면 어떻하삼? )
등등이 있겠다.

여기까지 들으면 더 자세한 내용은 PSM문서만 봐도 거의 이해가 될 것이다.


LiSPSM(Light Space Perspective Shadow Map)

PSM에 LiS(Light Space)만 붙어서, 난 기본 개념이 똑같은 줄로만 알았다.
근데 전혀 틀리게 시작한다 -_-;

일단 생소한 개념인(물론 얘네들이 새로 만들어서 이름붙인거니 다른곳에선 들어봤을리가..)
라이트 공간이 무엇인지 파악하는게 중요하다.

라이트 공간이란,

[그림출처 : LiSPSM문서. 라이트 공간 설정과 라이트 좌표계를 따르면서 뷰프러스텀을 포함하는 최소크기의 프러스텀 P를 소개하고 있다]

라이트 벡터L(소문자는 굴림체로 알아보기 힘들어서...)을 좌표축 y로 하고,
뷰벡터(ViewPoint - EyePosition 으로 구한다)V와 라이트 벡터L과의 외적을 좌표축 x,
그리고 y와 x의 외적을 좌표축 z로 갖는 좌표계 공간이다.

뷰 프러스텀을 라이트공간으로 투영 시키고,
좌표축에 딱 맞으면서 뷰 프러스텀에 최대한 가까운 크기를 갖는 프러스텀 P를 구하여,
요 프러스텀 P를 y축으로 투영시켜서 섀도우 맵을 뽑는 방식이다.
왜 y축이냐고? y축을 라이트 벡터로 잡았잖여 -_-

결론은, PSM에서 말하는 post-perspective상태랑은 전혀 틀리기 때문에 헷갈리지 말지어다...


TSM(Trapezoidal Shadow Maps)

TSM하면 사다리꼴. 사다리꼴 밖에 생각 안나는 분들이 많으실걸로 안다.
근데 사다리를 어쩌라고???

일단 장면(Scene)을 월드-뷰-프로젝션 변환을 시켜놓는다.
아까 PSM의 설명을 열심히 읽었다면, 현재 이 상태가 post-perspective상태라는 것을
기억할 수 있을 것이다.
(2008년 7월 19일 추가 : 월드-라이트뷰-라이트프로젝션 변환이다.)

프로젝션. 투영. 말 그대로 3차원을 2차원으로 변형한다는 의미이다.
그런데 PSM에서는 그렇게 왜곡된 상태에서 다시 3차원적 접근을 해버려서
알콩달콩한 문제들이 일어났는데,
TSM은 그상태 그대로. 2차원적으로 해결해버린다.

            [그림출처 : TSM설명 동영상. 저위의 바둑판 같은 것들은 프로젝션 변환후의 오브젝트들이란걸 의미하기 위함이다.
                            근데 전혀 티가 안난다;]

공간은 일단 WVP변환을 마친 상태이다.
(2008년 7월 19일 추가 : 월드-라이트뷰-라이트프로젝션 변환이므로 WLP 라고 쓰면 될려나?)
그리고 뷰 프러스텀을 구성하는 8개의 정점도 똑같이 변환해 주면 위의 그림같은 상황이 나온다.
(2008년 7월 19일 추가 : 정점 찾는 방법.
[0] = (-1, -1, 0), [1] = (-1, 1, 0), [2] = (1, 1, 0), [3] = (1, -1, 0),
[4] = (-1, -1, 1), [5] = (-1, 1, 1), [6] = (1, 1, 1), [7] = (1, -1, 1),
을 "뷰-프로젝션 의 역행렬"을 곱해준다.
저 좌표는 뷰 프러스텀의 8개 정점이 WVP변환 종료 후 갖게되는 좌표이므로,
(VP)^-1 을 해주면 정점들이 월드 좌표상으로 되돌아가게 된다.
그리고 이미 월드 변환은 적용 된 상태이니
남은 LP-라이트뷰, 라이트프로젝션- 변환만 해 주면
라이트-포스트 퍼스펙티브 상의 정점 좌표를 얻을 수 있게 된다.)

그 8개의 정점을 이용해(이미 여기서부터 공간은 2D 상황이다) 사다리꼴을 구성하는 4개의 정점을 뽑아내고
(TSM동영상을 보면서 고딩때까지 배웠던 수학적 지식을 총동원하면 못 구할것 없다)
다시 이 4개의 정점으로 이루어진 사다리꼴을 정사각형으로 변환시키는 행렬 Nt를 찾아내면
그걸로 TSM은 구현 끝이다.
행렬 Nt를 구하는 방법은 매우매우 친절하게 설명된 문서가 돌아다니고 있으므로 언급하지는 않겠다.

한가지, TSM은 저걸 개발한 대학인가 사람이 특허를 가지고 있어서 함부로 쓰면 좋치 않다는 소리가 있다.
실제로, 발매된 최신게임들은 다들 CSM(또는 PSSM) + LiSPSM(또는 SSM, PSM)의 조합을 채택하고 있다는 정보를
어렵지 않게 찾아볼 수 있을 것이다.(왜 조합이 필요한지는 CSM, PSSM 부분에서 설명하겠다)

효율은 LiSPSM보다 TSM쪽이 다소 좋다는 말이 있지만,
어차피 CSM(또는 PSSM)을 쓰게되면 그게 그거기 때문에
안전하게 LiSPSM로 가는거야~~


CSM(Cascade Shadow Mapping), PSSM(Parallel-Split Shadow Maps)

커스케이드. 직역하면 단계별 섀도우맵.
은근히 여기저기서 자주 대두되는 단어이다.
Parallel-Split는 네이년 사전에서 검색해 보니 '평행 분할' 정도로 직역할 수 있겠다.

아니 근데, 얘들은 왜 불쌍하게 한데 묶은겨?

사실 그놈이 그놈인기라.
구체적인 구현방법은 공부를 안해서 넘기고;
이 방식들은 한마디로 요걸로 표현할 수가 있다.

'밉맵이삼'

단지, 거리에 따라 텍스쳐 크기가 줄진 않는다;;

Depth Shadow Map알고리즘의 한계인 앨리어싱을
행렬 알고리즘으로 극복하는데에 한계를 느낀(그리고 텍스쳐 크기에도 한계를...) 님하들.

'그럼 많이 만들면 되잖아'

그런 것이다.
뷰프러스텀을 거리별로 일정 영역으로 나누어(3~4단계가량?)
각각 따로 섀도우맵을 뽑아놓는 무식하고도 확실한 방법이다.
                                              [그림출처 : PSSM문서. 닥치고 머릿수만 늘리면 모든게 해결이예요~]

즉, 텍스쳐 갯수를 늘리자는게 CSM, PSSM의 요지이기 때문에,
그 하나하나의 텍스쳐는 결국 SSM, PSM, LiSPSM, TSM중 하나를 택하여 구현하게 된다.
역시나 양에 장사없다고,
CSM, PSSM을 쓰면 딱히 SSM으로도 큰 문제는 없다고 한다 -_-;;

아참, 근데 도대체 CSM이랑 PSSM은 뭐가 다른거야? 라는 궁금증을 이제서야 풀어드리자면,
거리에 따라 섀도우맵을 새로 작성하게 되는데,
그 거리를 구하는 방식(알고리즘)이 다르댄다. -_-;

기분상으론 CSM이 기본 이론으로,
거기서 파생된게 PSSM이지 않을까 싶다.
이 부분도 추후 수정이 예상된다;;


LOGSM(Logarithmic Shadow Map)

요건 무엇에 쓰는 물건인고?

나도 며칠전에서야 처음 들어봐서
자료조차 본 적이 엄따.

들리는 얘기에 의하면
대수를 이용해서 TSM보다도 효율좋게 섀도우맵을 뽑는 방식이라던데,
현재의 GPU로는 실시간으로 계산할 수가 없댄다.
그냥 그런것도 있구나~ 하면 된다 -_-;



우아.... 적고보니 쎄( = 혀 )가 빠지는구나.
섀도우맵을 막 공부하기 시작하는 분들께 도움이 되었으면 좋을텐데말야.
사람이 와야 말이지. 이곳은 -_-;

덧글

  • 아뫼바군 2008/07/09 13:16 # 삭제 답글

    제 허접스런 글이 도움이 되었다 하시니 제가 되려 몸둘바를 모르겠습니다. 저도 이곳에 자주 들러 많이 배워 가겠습니다.
  • 아뫼바군 2008/07/09 14:28 # 삭제 답글

    아. 그리구 제가 알아본 LOGSM의 차이점은 일반 PSM은 선형왜곡(y = ax)을 시키는거에 비해 LOGSM은 로그곡선왜곡을 하는걸로 알고 있습니다.
    그렇게해서 그림자가 선명해지는 이유는.. 글쎄요... 저도 잘은 모르는데 시점의 방향과 라이트의 방향이 같을 일이 거의 없기 때문일꺼라고 추측중입니다.
    알게 되면 알려주세요.
  • x66vx 2008/07/10 12:06 # 답글

    아뫼바군님// 오오~ 방문해주셔서 감사합니다.
    "2008년 7월 8일 추가분" 위의 내용이 혼자 삽질하던 때이고,
    추가분 내용이 아뫼바군님 글 읽고나서 깨달음을 얻은 후 공부해서 개선한 내용입니다.
    글의 내용의 차이가 확연하지요 ^^;

    LOGSM은 한글로 설명해 놓은곳이 아무데도 없더군요 ㅠ.ㅠ
  • 홍지 2008/11/10 12:32 # 삭제 답글

    잘봤네요 저 초보라 Standard ShadowMap의 구체적인 원리에 에 대해서 알고프네요.
  • 홍지 2008/11/10 17:06 # 삭제 답글

    Pixel Shader를 리용하지 않고 그림자를 형상하는 방법이 있다는데 일명 Fixed Function ShadowMap 또는 SSM이 아닌죠.
    Pixel Shader를 리용하지 않고 그림자를 형상하는 방법좀 알켜주세요. ^^
  • x66vx 2008/11/10 23:49 # 답글

    홍지님// 반갑습니다.
    섀도우맵의 알고리즘은, 글 몇줄로 설명가능한 수준이 아니군요.
    (머리좋은 분들이 논문과 책을 써서 낸걸 저같은 허접이 몇줄 요약으로 전달해 드릴수 있을것 같지는 않습니다)
    섀도우맵으로 검색을 해보시면 자료그림도 풍부한 친절한 설명이 많이 있을겁니다.
    저같은 경우는 ShaderX 2권(국내 번역판 있음)을 보고 따라 구현했습니다.

    셰이더를 사용하지 않으시는거라면
    프로젝션 섀도우를 말씀하시는듯 합니다.
    평면 그림자라고도 합니다.

    평면 그림자의 전제조건은 '바닥이 굴곡없이 평평할것' 입니다.
    바닥이 평평하기 때문에 바닥을 하나의 평면방정식으로 표현이 가능합니다.
    오브젝트를 바닥 평면에 '투영' 시켜서 검은색으로 렌더링 하게 되면
    바닥에 투영된 검은 오브젝트가 그려지겠죠. 그게 평면 그림자입니다.

    즉, 그림자를 만들고싶은 오브젝트는 무조건 2번 그려야 합니다.
    하나는 바닥에 투영시켜서 그림자를 렌더링.
    또하나는 실제 오브젝트를 렌더링 하는것이죠.
  • 홍지 2008/11/25 18:00 # 삭제 답글

    네 ^^ 감사합니다.
    근데요. 저도 실지 쌤플을 봤거든요. 곡면에 떨어지면서 두번렌더링은 합니다. 하지만 쉐이더를 안써요.
    shadowmap을 떨구는 렌더 타겟은 L8형식으로 창조하고 걍 Fixed Function을 이용하는 방법이 있던데
    구체적으로 알고 계시면 부탁드립니다. ^^
  • 아뫼바군 2008/11/29 21:51 # 삭제 답글

    홍지님/
    Fixed 함수를 사용한 프로젝션 쉐도우는 쉐이더상수에 행렬을 넣느냐 SetTransform에 넣느냐 차이와 픽셀처리를 SetTextureStageState에서 해주느냐 픽셀쉐이더를 직접 건드느냐 차이로 알고 있습니다.
    SetTransform(D3DTS_TEXTURE(n), &LightProjectionMatrix ); <- 여기서 n은 그림자를 그려놓은 텍스처가 적용될 번호겠지요.
    LightProjectionMatrix를 구하는 방법은 똑같구요.
    실제로 2번 렌더링하는 것은 그림자를 드리우는 녀석만 2번 렌더링이 기본이구요.(까맣게 한번 실제 객체 한번)
    드리워지는 녀석은 멀티텍스처를 쓰면 1패스에 끝납니다.
    홍지님께서 질문하신 방법은 아주 특수한경우가 아니면 자기그림자가 나오지 않는 방법입니다. 물론 곡면에도 그림자는 드리워집니다.
  • x66vx 2008/12/02 23:26 # 답글

    아뫼바군님// 오랜만이예요 ^^ 반갑습니다.

    제가 잘 모르는 부분을 설명해주셔서 감사합니다.

    한마디로 API 고정 함수를 이용한 '데칼' 이로군요.
  • 아뫼바군 2008/12/05 11:47 # 삭제 답글

    x66vx님/
    앗. 제 블록까지 들러서 MRT에 관한 좋은 말씀까지 감사합니다.
    MRT라는것을 사용해본지 2시간도 안되서 이거 되게 좋네. 해서 바로 포스팅을 한거라 멋도 모르고 이게 좋은 점일것이다 해버린거였습니다.
    아유 쑥쓰러워라..
    --------------------------

    그런데 이글루를 보다보니 일본에 계신가보네요?
    저도 해외에서 일하고는 싶었는데 외국어쪽은 영 나가리라서.. 부럽네요오.
  • 일리아노 2009/01/22 14:27 # 삭제 답글

    그림자 관련 자료를 찾고 있었는데 엄청나게 많이 도움받고 갑니다 ^^ 즐거운 하루 되세요~.
  • x66vx 2009/01/22 22:58 # 답글

    일리아노님// 찾아와 주셔서 감사합니다.
    부족한 포스트인데 도움이 되었다니 다행입니다.

    저도 공부하면서 여러 블로그에서 도움을 많이 받았는데,
    작게나마 보답한 느낌이 들어서 무척 기쁘네요.
  • 홍지 2009/07/30 18:17 # 삭제 답글

    모두 반가워요. x66vx님이랑 아뫼바군 형님 ㅋㅋ
    오늘 LispSM에 대해서 잘 보고 갑니다. 직관적으로 잘 쓰셨네요^^
  • Hova_Moon 2012/01/06 00:30 # 답글

    우와 장난 아니네요~~ 그림자 부분 공부 하고 있었는데 참고 되고 있네요~정말 감사합니다~~!
  • 66v 2012/01/06 00:51 # 답글

    Hova_Moon// 답글 달아주셔서 감사합니다.
    이런 답글 볼때마다 괜히 설레고 기분 좋아지는걸 보면서
    왜 좀 더 좋은 정보를 많이 남기지 못했을까 반성하는 계기도 되네요.
  • 뎐삼 2012/02/11 16:28 # 삭제 답글

    자료감사합니다
    링크좀 해가겠습니다 ~ ^^
댓글 입력 영역
* 비로그인 덧글의 IP 전체보기를 설정한 이글루입니다.