본문 바로가기
셰이더 (Shader)/The Renderman Shading Language Guide

[RSL] Part1 : Your First Shader (66p ~ 91p)

by Minkyu Lee 2023. 5. 8.

 

 

Your First Shader : "Hello World Shader"

첫 번째 셰이더를 작성해보자.

 

RenderMan 셰이딩은 프로그래밍 언어인 RSL을 사용한다.

일반적으로 프로그래밍 언어를 소개할 때 사용하는 "hello world" 프로그램을 작성하자.

우리의 경우 "constant" 셰이더로 알려진 것을 작성할 것이다.

각 표면의 모든 점에 단일 값이 지정되어, 장면의 모든 조명을 완전히 무시한다.

이것은 쓸모없는 셰이더처럼 보일 수 있지만, 디버깅합성 매트를 만드는 데 유용하다.

 

다음과 같이 입력하라.

surface helloWorld()
{
Oi = Os;
Ci = Oi * Cs;
}

파일을 helloWorld.sl로 저장한다.

셰이더의 첫 번째 줄은 이 셰이더가 표면 유형임을 선언한다.

이름을 helloWorld로 지정한다.

 

다음은 괄호 안에 매개변수를 쓴다. 하지만 이 셰이더에는 매개변수가 없으므로 비워둔다.

다음으로 중괄호로 묶인 셰이더 본문을 연다.

이 괄호 사이의 모든 코드는 렌더러에 의해 평가되어, 표면의 초기 색상과 불투명도를 결정한다.

 

출력 불투명도(Oi)를, 입력 불투명도 (Os)로 설정한다.

출력 색상 (Ci)의 값을, 출력 불투명도 (Oi)와 입력 색상 Cs으로 설정한다.

 

마지막으로 불투명도(opacity)에 색상을 곱하는 것은 컴포지팅에 대한  pre-multiplied alpha 마스크를 생성하기 때문에

셰이더에서 일반적인 방식이다.

 

불투명도 처리에서 일관성을 유지하는 것이 좋다.

일부 셰이더에서는 불투명도를 미리 곱하고, 다른 셰이더에서는 그렇지 않으면 문제가 발생할 수 있다.

 

이 셰이더를 컴파일해보자.
Shadercmd helloWorld.sl


모든 것이 올바르게 입력되었다면, 셰이더가 컴파일되었다는 메시지가 나온다.

확장자가 xxx인 helloWorld.xxx 파일도 생성된다.

이 xxx는 사용하는 렌더러의 확장자이다.

 

이제 sphere.rib 파일을 열고 surface 호출을 다음과 같이 변경해보자.
Surface "helloWorld"

 

컴파일된 helloWorld 셰이더와 동일한 디렉토리에 수정된 파일을 저장하고 렌더러 명령을 사용하여 렌더링하자.

다음과 같이 입력하라.
rendercmd sphere.rib


모든 것이 정상적으로 진행되면 그림 3.5에 나와 있는 것과 같이 검은 배경에 흰색 원이 나타난다.

이 원은 실제로는 구이다.

하지만 조명 계산이 이루어지지 않으므로 실루엣만 보인다.

 

Adding Color and Opacity Control

셰이더에 색상 및 불투명도 컨트롤을 추가해보자.

몇 가지 셰이더 매개변수를 추가하는 것이다.

사용자가 컨트롤 할 수 있게 된다.

helloWorld.sl을 수정해보자.

surface helloWorld(
    color surfaceColor = color (1,1,1);
    color surfaceOpac = color (1,1,1);
    )
{
Oi = surfaceOpac;
Ci = Oi * surfaceColor;
}

 

이제 셰이더를 컴파일하자.

surfaceColor의 값을 수정하려면 sphere.rib 파일에서 다음과 같이 변경한다.

Surface "helloWorld" "color surfaceColor" [1 0 0]

 

sphere.rib 파일을 저장하고 렌더링하면 이제 검은색 배경 위에 빨간색 구가 나타난다.
표면색을 빨간색으로 지정했기 때문이다. (그림 3.6 참조).

 

Ambient Illumination

셰이더가 씬의 조명과 상호작용 할 수 있도록 몇 가지 컨트롤과 기능을 추가한다.

 

첫번째, 가장 기본적인 조명 유형은 앰비언트 조명이다.

앰비언트 조명은 표면의 모든 지점에서 균일하다.

빛을 묘사하는 매우 오래되고 저렴한 방법이다.

 

이 장의 앞부분에서 설명한 오클루전 패스와 결합되어 사용되며,

후반부에서 자세히 다룰 예정입니다. 

 

우선, 앰비언트 조명을 추가해보자.

helloWorld.sl을 다음과 같이 변경해보자.

surface helloWorld(
    uniform float Ka = 0.5;
    color surfaceColor = color (1,1,1);
    color surfaceOpac = color (1,1,1);
    )
{
Oi = surfaceOpac;
Ci = Oi * surfaceColor * Ka * ambient();
}

 

이제 "엠비언트의 계수 (coefficient)"를 나타내는 Ka라는 매개 변수를 셰이더에 추가했다.
Koefficient에 대한 K를 사용하기 시작한 것은, 용어를 처음 사용한 사람이 독일인이었기 때문이다.

 

셰이더를 컴파일하고 sphere.rib을 다시 렌더링한다.

밝은 빨간색 구체는 이제 어두운 빨간색으로 약해진다.


Ka 값이 0.5이므로 이 값은 앰비언트 라이트 강도, surfaceColor 및 surface opacity와 곱해집니다. 

이것이 표면이 강도의 절반으로 어두워진 이유이다. 

그림 3.7을 확인해보자.

 

Lambert Illumination

앰비언트 조명은 매우 지루하고 평면적이다.

입체감을 주려면, 조명이 닿은 곳은 밝고, 그렇지 않은 곳은 어두워져야한다.

난반사 조명(diffuse illumination)이 필요하다.

 

Lambert 조명 모델은 가장 기본적인 난반사 모델이다.

RSL은 이러한 값을 계산하는 함수를 제공한다.

 

Lambert 조명 모델은 이후 장에서 자세히 설명될 것이다.

그래서 우선 함수를 사용해보자.

helloWorld.sl 파일을 다음과 같이 수정하라.

surface helloWorld(
    uniform float Ka = 0.5;
    uniform float Kd = 0.85;
    color surfaceColor = color (1,1,1);
    color surfaceOpac = color (1,1,1);
    )
{
/* Variables */
normal Nn = normalize(N);
Oi = surfaceOpac;
Ci = Oi * surfaceColor * (Ka * ambient() + Kd * Diffuse(Nn));
}

 

반사하는 양을 제어하는 Kd (난반사 계수) 매개변수를 추가했다.

또한 Nf 변수를 선언하여 정규화된 법선을 저장한다.

 

마지막 줄은 엠버언트와 난반사를 더한 값을,

표면 색상과 불투명도에 곱하는 방식으로 수정하였다.

 

셰이더를 컴파일해보자.

sphere.rib을 다시 렌더링하면 빨간색 구의 이미지를 볼 수 있다.

 

Specular Reflections

마지막 단계는 specular를 추가하는 것이다.

플라스틱처럼 보이게도 할 수 있다.

 

또한 specular highlight 색상을 조절할 수 있는 매개변수도 추가할 것이다.

이러한 방식으로 매우 간단하고 기본적인 금속 등 여러 가지 표현을 할 수 있다.

 

더 고급진 금속 같은 외관을 얻으려면 반사 구성요소를 추가해야한다.

반사와 레이트레이싱을 사용하는 고급 방식은 14장에서 다룰 예정이다.

스펙큘러 반사(reflection)를 계산하기 위해 사용 가능한 다양한 모델들이 있다.

그 중에서 Phong Blinn이 가장 인기 있는 모델이다.

 

렌더러는 스펙큘러 함수를 제공하기도 한다.

함수가 계산되는 방법은 각 렌더러마다 다르기 때문에 렌더러별 결과가 다를 수 있다.

다음은 specular highlight을 포함하는 helloWorld.sl 내용이다.

surface helloWorld(
	uniform float Ka = 0.5;
	uniform float Kd = 0.85;
	uniform float Ks = 1;
	uniform float roughness = 0.2;
	color surfaceColor = color (1,1,1);
	color surfaceOpac = color (1,1,1);
	color specularColor = color (1,1,1);
	)
{
/* Variables */
normal Nn = normalize(N);
vector V = -normalize(N);
Oi = surfaceOpac;
Ci = Oi * surfaceColor * (Ka * ambient() + Kd * Diffuse(Nn)) +
	specularColor * Ks * specular(Nn,V,roughness);
}

 

여기서 멈추지 않고, 쉐이더에 계속해서 기능을 추가해볼 수도 있다.

하지만, 이제는 코딩 예제를 멈추고, 쉐이딩의 기본 CG 개념을 알아야 할 때이다.

적절한 쉐이딩 개발 환경을 설정하고, 쉐이더 작성에 대한 방법론과 접근 방식에 대해 논의할 것이다.

댓글