http://blog.naver.com/pch413/10001173790
< 자작 해칭 예제 스크린샷 >
아주~아주~아주~ 오래전에 제가 회사에서 세미나하고 올린
해칭 관련 예제 포스트(http://blog.naver.com/pch413/7330265)를 보시고
세부 구현이나 관련 자료를 문의하시는 분들이 가끔~가끔~ 계셨습니다.
(사실 REAL-TIME RENDERING 2nd Edition 책 보면 다 나옵니다.)
사실 자작 구현이라기 보다는 책에 있는 내용을 공부삼아 HLSL로 옮겨본 것 밖에 없고,
귀찮기도 하고 소스가 별로 깔끔하지도 못하고 엉망이라서 공개를 꺼렸는데...
이래저래 문의하시는 분들이 나중에도 생기면 더 귀찮아질 수도 있으므로
예제 실행 파일과 함께 HLSL 소스까지 공개합니다.
첨부된 HatchTest_060123_parkch.zip 압축파일을 받아서 적당한 곳에 풀어놓으신 후,
HatchTest 폴더 안에 있는 HatchTest.exe를 실행시키시면 예제를 돌려보실 수 있습니다.
HLSL 소스는 HatchTest.fx 파일을 참조하시면 됩니다.
예제를 실행하실려면 DirectX 9.0c 런타임 최신 버전이 깔려있어야 합니다.
그리고 Vertex Shader 1.1 이상, Pixel Shader 1.4 이상을 지원하는
그래픽 카드(ATI RADEON 8500급 이상)가 있어야 합니다.
실행시키시면 가상 광원의 위치를 나타내는 노란색의 구(sphere)가 물체 주위를 빙글빙글 돌아가는 것을 보실 수 있습니다. 그리고 그 광원 위치에 따라 해칭 패턴이 변화하게 됩니다. 마우스로 물체를 회전시킬 수도 있으니 조작해보시길 바랍니다. 그리고 우측에 있는 콤보 박스를 이용하면 표시되는 물체(구, 원뿔, 주전자, 호랑이)를 바꿀 수 있습니다.
< 해칭의 개념 >
해칭(Hatching) : 펜/잉크 소묘에서 가늘고 세밀한 평행선이나 교차선을 사용하여 객체의 음영 차이 및 요철을 표현하는 기법에 대한 일반적인 용어.
(개념 : 인간이 마땅히 알아야 할 상식과 도리로서 이를 알지 못하면 '개'가 된다고 하여 개념이라 함.)
이 예제에서 보여주는 해칭(Hatching)은 비실사 렌더링(Non-Photorealistic Rendering;NPR) 방식 중의 하나로서 해치 패턴의 밀도를 통해 그 지점의 표면이 얼마나 많은 빛을 반사하는지를 표현해주는 기법입니다. 여기서 사용하는 해칭 기법은 매우 드문드문한(빛을 많이 받는) 영역으로부터 매우 조밀한(빛을 받지 않는) 영역에 이르는 해치 패턴 맵을 이용하게 됩니다. 각 정점 별로 빛에 대한 가중치를 계산한 다음, 각 픽셀 별로 보간된 가중치에 따라 해치 패턴 맵을 적절히 혼합하여 표현해주는 방법을 사용하고 있습니다.
< Tonal Art Maps >
어떤 분께서 E-Mail로 Tonal Art Map(TAM)을 이용해서 구현했는지 물어보셨는데, 맞습니다.
앞서 언급한 해칭 패턴 맵이 바로 Tonal Art Map으로서 여기서는 6단계의 텍스처를 사용하게 됩니다.
하지만, 팔레트가 6개-즉, 텍스처를 6장이나 쓰게 되면 그만큼 처리 비용이 엄청나겠죠?
그래서 위의 그림과 같이 각 단계의 맵이 단색(Grayscale)임을 이용하여
텍스처의 각 색상 채널에 하나씩 할당해서 2장의 텍스처로 줄여 쓸 수 있게 합니다.
(단색 텍스처는 0~255 값을 가지는 하나의 채널로 표현할 수 있으므로
R, G, B 각각의 채널에 하나씩 집어넣을 수 있습니다.)
즉, 1,2,3 단계의 맵은 첫번째 텍스처, 4,5,6 단계의 맵은 두번째 텍스처에 할당됩니다.
(첨부된 압축 파일 안의 Hatch123.dds, Hatch456.dds가 이것입니다.)
이 내용은 "REAL-TIME RENDERING 2nd Edition" 책에 소개된 기법으로서
2001년 시그라프(SIGGRAPH) 논문에 있는 내용입니다.
Emil Praun, Hugues Hoppe, Matthew Webb, and Adam Finkelstein, "Real-time Hatching," (SIGGRAPH Proceedings, 2001), pp. 581-586.
아래 링크를 클릭해보시면 논문을 직접 보실 수 있습니다.
http://research.microsoft.com/~hoppe/hatching.pdf
(다소 영어의 압박을 느낄 수도 있습니다.)
< Vertex program source >
위의 소스는 정점 프로그램으로서 각 정점 별로 빛에 대한 가중치를 계산합니다.
워낙 코딩 실력이 딸려서 소스가 복잡하고 다소 더럽지만 그렇다고 나무라지는 마시길 바랍니다.
clamp, abs 함수들을 좀 복잡하게 써 놓긴 했지만, 내용은 단순합니다.
(abs는 절대값, clamp는 min~max 밖의 값을 잘라냄; max보다 크면 max로, min보다 작으면 min으로 함.)
쉽게 설명하면, 정점에 대한 노말 벡터와 광원 방향 벡터의
내적을 구해서 빛을 받는 정도를 [-1, 1] 구간 사이로 구한 다음, [0, 6] 구간으로 바꿉니다.
그리고나서 가장 적합한 단계들에게 가중치를 부여합니다.
예를 들어, 'n dot l'의 계산 결과가 0.5가 나왔다고 합시다. 어중간하게 좀 밝은 쪽이 되겠죠?
그러면, 1단계와 2단계 텍스처가 중간 정도 혼합된 형태가 되어야 할 것입니다.
위의 복잡한 식대로 계산하면 oTexWeight123과 oTexWeight456은 다음 값들을 가지게 됩니다.
oTexWeight123 == (0.5, 0.5, 0.0)
oTexWeight456 == (0.0, 0.0, 0.0)
의도한 대로 1단계와 2단계에 0.5씩 가중치가 들어갔죠?
한마디로, abs랑 clamp를 써서 적절한 단계에 가중치가 부여될 수 있도록 했습니다.
만일, 이 글을 보시는 다른 분들께서 조금 더 간단하게 쓸 수 있다고 생각하시면 알려주세요.
아직 HLSL를 많이 써보지 못하다보니 코드가 좀 엉망입니다.
(지금 생각해보니 clamp(..., 0.0, 1.0)이 아니라 saturate(...)를 쓰면 되었을 것을... 왜 저랬을까? 이런 바보같은 짓을... ㅡㅡ;)
< Fragment program source >
마지막으로 위의 소스는 프래그먼트 프로그램으로서
각 픽셀 별로 보간된 가중치에 따라 TAM을 혼합하게 됩니다.
앞 쪽에서 보여드린 TAM 그림을 다시 보시면 스트로크(stroke) 패턴들이 검정색,
바탕은 흰색으로 된 것을 알 수 있습니다.
사실 우리가 해야 할 일은 스트로크 패턴들만 뽑아내서 잘 혼합하는 것입니다.
그래서 이 프래그먼트 프로그램에서는 별도로 구현된
GetInverseColor 함수를 이용해서 색상을 뒤집습니다.
즉, 바탕이 검정(0.0)으로 바뀌고, 스트로크가 흰색으로 바뀌므로
스트로크 요소만 따로 혼합될 수 있습니다.
보간된 가중치를 각 채널에 들어있는 Grayscale 값과 곱해서 더하고,
이를 다시 GetInverseColor 함수로 뒤집어주면 우리가 원하던 최종 색상을 얻어낼 수 있게 됩니다.
< 참고 자료 >
1) Real-Time Rendering(2nd Edition)/Tomas Akenine-Moller, Eric Haines/A.K.Peters Limited
해칭 관련 내용은 이 책 보고 쁼(feel) 받고
실제로 돌려보고 싶다는 생각이 들어서 HLSL로 구현해봤던 겁니다.
현존하는 실시간 렌더링 관련 서적 중에서는 최고의 참고서입니다.
7장의 Non-Photorealistic Rendering 파트에 해칭 관련 내용이 소개되어 있습니다.
2) Direct3D ShaderX:Vertex and Pixel Shader Tips and Tricks/Wolfgang F. Engel/Wordware Publishing
사실 제 소스는 이 책에 있는 어셈블리로 작성된 해칭 소스를 거의 베끼다시피해서 HLSL로 옮긴 것에 불과합니다. 그리고 TAM 텍스처도 부록 CD 안에 들어 있는 것을 가져와서 쓴 것입니다. 원본 소스를 보고 싶으시다면 참조하십시오.
< 마침 >
간만에 긴 글을 포스팅해봤습니다. HLSL 써본지도 꽤 오래된 지라 가물가물하기도 하고, 글도 생각처럼 잘 써지지도 않는군요. 그리고 나름대로 머리 좀 굴려봤다고 자부했었는데... 오히려 글을 쓰고 보니 부족했던 점이 더욱 눈에 띕니다. 제가 참여하고 있는 프로젝트도 셰이더를 맘껏 쓸 수 있는 환경이 되면 좋겠지만... 렌더링과는 점점 더 멀어지는 일만 하고 있네요. 좀 더 재미있는 것을 할 수 있다면 좋으련만...
오뎅장수 P군
'그래픽스(Graphics) > Shader' 카테고리의 다른 글
DirectX 9.0 셰이더 프로그래밍 강의 (0) | 2013.01.08 |
---|---|
셰이더[Effect] 함수들 ID3DXBaseEffect 인터페이스 (0) | 2013.01.08 |
VS에서 HLSL 편집하기 InteliShade (0) | 2013.01.05 |
쉐이더 기법 (0) | 2012.11.02 |
셰이더 내장함수 (0) | 2012.11.02 |