Graphics Programming

전방향 그림자 매핑(omnidirectional shadow mapping) 본문

Season 1/OpenGL

전방향 그림자 매핑(omnidirectional shadow mapping)

minseoklee 2016. 1. 24. 11:41

방향광(directional light)을 이용해 기초적인 그림자 매핑을 구현하고 나니 3년도 전에 본 그림이 생각났다.


http://9gag.com/gag/1744243/lamp-level-asian


기본적인 그림자 매핑은 한 방향으로만 그림자를 그리기에 전방향으로 그릴 수가 없다. 점광원의 위치에서 여섯 방향으로 깊이 맵을 그리고 각각의 맵을 큐브맵의 여섯 면에 대응하면 되지 않을까 싶었고, 검색해보니 실제로 큐브맵을 이용해 전방향 그림자 매핑을 구현하는 것이 보편적이었다. 그림자 매핑을 여섯 번 하면 되는 아주 쉬운 작업이라고 생각하였으나 구현하는 과정에서 멘탈이 수없이 깨졌다.


- 큐브맵 텍스처의 샘플링. 큐브맵 텍스처의 각 면(face)에 RGBA 텍스처가 아니라 깊이 텍스처를 붙이는 것이 가능하다. 프래그먼트 셰이더에서는 cubeSamplerShadow 타입의 샘플러로 깊이값 테스트를 하는데, 레퍼런스를 보니 인자가 vec3다...? 비교할 깊이값을 명시해야 하는데 vec3로는 방향 벡터만 나타낼 수 있다. 레딧에 질문을 올리니 vec3가 아니라 vec4라는 답변이 달렸고, 찾아보니 OpenGL 4.5버전의 레퍼런스에는 vec3로, 4.4에는 vec4로 나왔다. 그리고 vec4가 맞다. 없던 오타가 최신 문서에서 오히려 생기는 마술


- 각 면에 붙일 텍스처의 크기와 포맷 등을 지정해야 하는데 glTexStorage2D()를 썼다가 실패했다. 프레임버퍼 무결성 검사가 실패했다는 로그가 찍혔는데도 못 보고 한참을 해메다가 glTexImage2D()로 바꾸고 성공했다.


- 셰이더 프로그램에서 mvTransform 유니폼에 값을 입력해야 하는데 vpTransform이라고 오타를 내놓고 발견을 못해 시간을 날렸다. 이후로 셰이더에 문제가 있는 것 같으면 꼭 glGetUniformLocation()이 -1을 반환하는지 확인한다.


- 2D 텍스처에서는 u, v의 범위가 [0, 1]인데 큐브맵 샘플링에서는 x,y,z의 범위가 [-1, 1]이다. 범위를 조정하는 걸 깜빡해놓고 왜 깊이맵의 1/4 영역만 샘플링되는지 또 한참 고민.


- 오류 없이 모든 게 정상인데 그림자가 안 그려져서 한참 디버깅. 원인은 깊이맵을 그리기 전에 벽을 그리는 거였다. 깊이맵이 없으니 당연히 벽에 드리울 그림자가 없다. 으아아아!!! 나는 멍청합니다!!!


각각은 사소한 오류지만 원인을 파악하는 데 최소 서너 시간이 걸렸기 때문에 내게 OpenGL을 디버깅하는 능력이 한참 모자라다는 걸 깨달았다. 디버깅 컨텍스트를 쓰면 편하다는데 무슨 APIENTRY 상수를 못 찾아서 콜백 함수 정의가 안 된단다.



어쨌든 완성하고 나니 뿌듯하다.


램프 모델은 블렌더로 쉽게 만들 수 있었다.


Comments