강좌를 보기 전에...
Cygwin 설치방법
REYES
Shader 강좌 1
Shader 강좌 2
Shader 강좌 3
Shader 강좌 4
Shader 강좌 5
Shader 강좌 6
Shader 강좌 7
Shader 강좌 8
안녕하세요. 김대현입니다.

시작하기 전에 3가지 의문점이 있습니다.

첫번째, 쉐이더 코드를 직접 작성해 보는 이유는 뭘까요 ?

Slim이나 VOPs등으로 얼마든지 훌륭한 쉐이더를 만들 수 있습니다. 하지만 문제가 발생했을때, 결국은 소스 코드의 내용을 분석할 수 있는 능력이 있어야 합니다.

배울때는 최대한 손으로 직접하는 것이 좋습니다. 게다가 Slim등의 툴은 초보자가 쉽게 만들라고 만든 툴이 아니라 소스를 이해하는 사람이 빨리 만들라고 만든 툴이라고 생각합니다.

두번째, 넓은 면적에 불규칙한 모양을 넣어야 한다면?

텍스쳐를 사용하면 현실감이 극적으로 향상되게 됩니다. 하지만, 도대체 텍스쳐의 해상도는 어느정도여야 할까요? 그리고 그 소스는 어디서 구하면 좋을까요?

넓은 면에 텍스쳐를 적용할 경우 높은 해상도의 텍스쳐가 필요합니다. 그러려면 사진을 찍거나, 잡지를 스캔해서 사용하게 되는데, 높은 해상도의 텍스쳐를 얻기 쉽지 않습니다. 그래서 텍스쳐를 타일로 적용하게 되는데, 현실감을 떨어뜨리는 요소가 됩니다. 게다가 불규칙한 모양을 모두 얻을 수도 없습니다.

그렇다면 대안은 텍스쳐를 직접 만들면 되겠군요. 직접 만드는 방법 중 직접 그리는 방법이 있겠군요. 하지만, 넓은 면적에 불규칙한 문양이 들어가야 한다면, 그 불규칙한 모양을 다 그려야 할까요 ? 역시나 답이 아닙니다.

답은 수학적 연산으로 직접 모양을 만들어 내는 것입니다. 이걸 프로시주얼 텍스쳐라고 합니다. 아무리 넓은 면이라도 해상도에 관계없이 프렉탈한 텍스쳐를 붙일 수 있습니다. 수치만 조금 조정해도 얼마든지 불규칙한 모양을 얻어낼 수 있으므로 넓은 면적에 불규칙한 모양의 텍스쳐로는 더없는 선택이겠네요.

물론 극히 일부분에만 사용되는 경우겠지만, 사용자에게 더욱 많은 선택권을 준다는 점에서는 강점이라고 하겠네요.

세번째, 쉐이더 코드는 왜 작성할까요 ?

쉐이더 코드를 작성할 수 없는 렌더러의 경우 고정된 Blin, Phong등의 알고리즘만을 사용할 수 있습니다. 하지만 쉐이더 코드를 작성할 수 있다는 것은 새로운 알고리즘의 쉐이딩이 나왔을때, 그걸 바로 적용할 수 있다는 점이죠. Blin, Phong등의 기존 알고리즘뿐만 아니라 새로 개발되는 알고리즘을 적용하기 쉬워지는 점이 있습니다.






자~자~~ 서론이 너무 길었습니다. 본격적으로 쉐이더 코드를 작성해 보죠.

전 시간에 쉐이더만 간단히 테스트할 수 있는 환경을 셋팅했는데요. 이번 시간에는 그걸 사용하지 않고 직접 모두 해 보겠습니다.

1. 자~ 노트 패드를 여시고~~

test2.rib ( 소스 1 )
-----------------------------------------------------------

Display "test2.tiff" "tiff" "rgb"
Format 16 16 1
Projection "orthographic"
ShadingRate 100

WorldBegin
        Translate 0 0 1
        Surface "test2"
        Polygon "P" [0 0 0 1 0 0 1 1 0 0 1 0]
WorldEnd


-----------------------------------------------------------



test2.sl ( 소스 2 )
-----------------------------------------------------------

surface test2()
{
        printf("test2 surface shader called.\n");
        Oi = Os;
        Ci = Cs * Os;
}


-----------------------------------------------------------


2. 우선 쉐이더를 컴파일해 보죠. ($는 입력하는 것이 아닙니다. 프롬프트입니다. )

$ shader test2.sl
test2: compiled.

3. test2: compiled.라고 출력되면서 test2.slo가 생겼습니다.

4. 그럼 이제 렌더러에게 렌더시켜 보죠.

$ prman test2.rib
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.



5. test2 surface shader called. 가 네번 출력되었습니다.

6. 우리만 만든 쉐이더 코드가 4번 호출되었군요.

7. 왜 4번 호출되었을까요 ?
답은 Format과 ShadingRate에 있습니다. 전 시간에 REYES 알고리즘에 관해 설명드린 적이 있습니다.

Format의 경우 이미지의 해상도로 여기서는 16x16 픽셀짜리 이미지로 지정하였습니다.

ShadingRate는 100으로 지정하였는데, Micropolygon의 면적이라고 말씀드렸습니다.

그렇다는 것은 ShadingRate가 100이란 것은 micropolygon 이 최소 10픽셀 크기라는 얘기겠군요.

그럼 우리가 계산하는 쉐이더는 microplygon의 버텍스 단위로 연산된다고 말씀드렸습니다.

슬슬 답이 보이지 않습니까 ?

맞습니다. 16 픽셀짜리 이미지에, 크기 1짜리 polygon이 있고 micropolygon의 크기는 최소 10픽셀이므로 rib에서 만든 polygon의 크기가 microplygon보다 작겠네요. 그렇다는 것은 우리 polygon이 micropolygon 하나 안에 쏙 들어가고, 쉐이딩이 각각의 micropolygon 4개의 버텍스를 연산하므로 4번 호출된 것입니다.

8. 이로써 무언가 어렴풋했던 micropolygon의 개념이 와 닿지 않습니까 ? ShadingRate 값을 줄이거나, Format으로 이미지 사이즈를 늘리면 더 많이 호출될 것입니다. 즉 primitive가 더 잘게 micropolygon으로 잘라져서 연산되었다는 의미죠.

9. 이왕하는 김에 좀 더 놀아보죠.

10. light shader를 만들어 봅시다.


test2light.sl ( 소스 3 )
-----------------------------------------------------------

light test2light()
{
        printf("test2 light shader called.");
        Cl = color (1.0, 1.0, 1.0);
}


-----------------------------------------------------------


11. 그리고 test2.rib를 다음과 같이 수정합니다.

test2.rib ( 소스 4 )
-----------------------------------------------------------

Display "test2.tiff" "tiff" "rgb"
Format 16 16 1
Projection "orthographic"
ShadingRate 100
LightSource "test2light" 1

WorldBegin
        Translate 0 0 1
        Surface "test2"
        Polygon "P" [0 0 0 1 0 0 1 1 0 0 1 0]
WorldEnd


-----------------------------------------------------------

12. LightSource라는 키워드가 추가되었습니다.

13. 자~ 우리의 light shader를 컴파일해 보죠.

$ shader test2light.sl
test2light: compiled.


14. 그럼 우리의 light shader와 surface shader로 렌더해 볼까요 ?

$ prman test2.rib
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.



15. 어라~ 예전하고 변화가 없네요 ? 어떻게 된 일이죠 ? 우리의 light shader가 전혀 호출되지 않고 있습니다.

16. 이유는 surface shader와 light shader의 관계에 있습니다. 라이팅 계산이란 무엇일까요 ?

그것은 표면에 색상이나 밝기를 계산하기 위해 있는 것이지 자체만으로는 의미가 없습니다. 그렇다는 것은 surface를 계산할때, 라이팅을 적절히 호출하여 자신의 표면과 빛의 관계를 계산해야 겠군요.

17. 그렇다면, 우리의 surface shader를 조금 수정하여 라이팅을 계산하게 해 봅시다.

test2.sl ( 소스 5 )
-----------------------------------------------------------

surface test2()
{
        printf("test2 surface shader called.\n");
        Oi = Os;
        Ci = Cs * Os * ambient();
}


-----------------------------------------------------------

18. test2.sl과 test2light.sl을 다시 컴파일하고 렌더링해 봅시다.

$ prman test2.rib
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.
test2 surface shader called.
test2 light shader called.
test2 light shader called.
test2 light shader called.
test2 light shader called.



19. 오~예~~! 우리의 라이팅이 계산되는게 보입니다.

20. 이 예제에서 우리는 라이팅 계산보다는 surface shader와 light shader의 관계를 보여주기 위한 것이었습니다.

21. 다음 시간에는 처음 시간에 셋팅한 환경에서 본격적으로 surface shader를 만져봅시다.



예제 소스 : shader_2.zip