ashen-aetna-ko

잿빛 에트나(Ashen Aetna)

— 재 덮인 화산 위에서 어설프게 비틀거리기

(3D 그래픽스, Rust, Vulkan, ash에 대한/속의/관한/과 함께하는 튜토리얼)

셰이더 간 데이터 전달

우리가 그려온 점은 빨간색이었습니다. 프래그먼트 셰이더에 이 색상을 하드코딩했었죠:

	#version 450
	
	layout (location=0) out vec4 theColour;

	void main(){
		theColour= vec4(1.0,0.0,0.0,1.0);
	}

물론, 다른 색을 원한다면 여기서 그냥 바꾸면 됩니다. 예를 들어

		theColour= vec4(1.0,0.5,0.0,1.0);

이나

		theColour= vec4(0.0,0.0,1.0,1.0);

을 시도해 보세요. 하지만 각기 다른 지점에서 다른 색상을 얻는 방법을 보는 것이 더 흥미로울 수 있습니다. 또는 더 일반적으로, 값을 하드코딩하지 않고 프래그먼트 셰이더로 데이터를 가져오는 방법을 알아보는 것이죠.

프래그먼트 셰이더를 위한 데이터의 한 가지 출처는… 버텍스 셰이더일 수 있습니다. 버텍스 셰이더가 프래그먼트 셰이더 직전에 실행된다는 점을 고려하면 말이죠.

우리의 계획에 대해 양쪽 셰이더 모두에게 알려줘야 합니다: 프래그먼트 셰이더에게는 어떤 값이 들어온다고 알려주고:

	#version 450
	
	layout (location=0) out vec4 theColour;

	layout (location=0) in vec4 data_from_the_vertexshader;

	void main(){
		theColour= vec4(1.0,0.0,0.0,1.0);
	}

그리고 그 값을 어떻게 처리할지도 알려줘야겠죠 (이전에 사용했던 빨간색 값 대신 사용하도록):

	#version 450
	
	layout (location=0) out vec4 theColour;

	layout (location=0) in vec4 data_from_the_vertexshader;

	void main(){
		theColour= data_from_the_vertexshader;
	}

그리고 버텍스 셰이더에게는 이 데이터를 출력하라고 알려주고 (그리고 어떤 값을 줘야겠죠):

	#version 450

	layout (location=0) out vec4 data_from_the_vertexshader;

	void main() {
	    gl_PointSize=10.0;
	    gl_Position = vec4(0.4,0.2,0.0,1.0);
	    data_from_the_vertexshader=vec4(0.0,0.6,1.0,1.0);
	}

자, 이제 점은 더 이상 빨간색이 아닙니다. 성공했네요.

우리가 추가한 코드를 살펴봅시다: vec4라는 데이터 타입이 있었고, 좋습니다. 그리고 셰이더로 들어오는 데이터를 위한 in과, 음, 출력을 위한 out이라는 꽤 명확한 키워드가 있었습니다.

그럼 변수 이름은 어떨까요? 제 말은, 양쪽 셰이더에서 변수 이름을 data_from_the_vertexshader라고 지었는데, 이게 꼭 필요했을까요?

한번 시험해 보죠. 프래그먼트 셰이더는 그대로 두고, 버텍스 셰이더를 다음과 같이 바꿔봅시다:

#version 450

layout (location=0) out vec4 colourdata_for_the_fragmentshader;

void main() {
    gl_PointSize=10.0;
    gl_Position = vec4(0.4,0.2,0.0,1.0);
    colourdata_for_the_fragmentshader=vec4(1.0,0.6,1.0,1.0);
}

여전히 잘 작동하나요? 유효성 검사 레이어에서 오류 메시지도 없고요? 아주 좋습니다.

참고: 변수들은 다른 셰이더에서 그 이름으로 식별되지 않습니다.

그리고 바로 이 지점에서 layout (location=0)의 의미가 중요해집니다. 한번 바꿔보죠:

#version 450

layout (location=1) out vec4 colourdata_for_the_fragmentshader;

void main() {
    gl_PointSize=10.0;
    gl_Position = vec4(0.4,0.2,0.0,1.0);
    colourdata_for_the_fragmentshader=vec4(1.0,0.6,0.0,1.0);
}

모든 것이 검은색입니다. (그리고 제가 색상을 다시 바꿨기 때문이 아닙니다. 숫자를 보면 여전히 전혀 검은색이 아니거든요. 정말 고맙게도 말이죠.)

하지만 이 문제의 해결책은 그리 터무니없어 보이지 않습니다: 프래그먼트 셰이더도 수정해서 입력 변수의 location을 맞춰줍시다.

	#version 450
	
	layout (location=0) out vec4 theColour;

	layout (location=1) in vec4 data_from_the_vertexshader;

	void main(){
		theColour= data_from_the_vertexshader;
	}

이제 다시 괜찮아졌습니다.

이건 어떨까요?

#version 450

layout (location=0) out vec4 theColour;

layout (location=5) in vec4 data_from_the_vertexshader;

void main(){
	theColour= data_from_the_vertexshader;
}

와 이걸 함께 사용하면요?

#version 450

layout (location=5) out vec4 colourdata_for_the_fragmentshader;

void main() {
    gl_PointSize=10.0;
    gl_Position = vec4(0.4,0.2,0.0,1.0);
    colourdata_for_the_fragmentshader=vec4(0.4,1.0,0.5,1.0);
}

다시 한번: 작동합니다. 한 셰이더의 변수 출력은 다음 셰이더에서 그 위치(location)로 인식됩니다. 이 위치는 셰이더 프로그램에서 변수를 선언할 때 in 또는 out 키워드 앞에 layout (location=5)와 같은 레이아웃 지시자(layout directive) 형태로 주어집니다.

프래그먼트 셰이더에서

	#version 450
	
	layout (location=0) out vec4 theColour;

	layout (location=0) in vec4 data_from_the_vertexshader;

	void main(){
		theColour= data_from_the_vertexshader;
	}

우리는 또한 “in”과 “out” 변수가 이 슬롯들에 대해 별도의 열거를 가진다는 것을 알 수 있습니다. 입력(in)의 location 0은 출력(out)의 location 0과 같지 않습니다.

이제 색상은 더 이상 프래그먼트 셰이더에 하드코딩되어 있지 않습니다. 버텍스 셰이더에 하드코딩되어 있죠. 이제 버텍스 셰이더로 데이터를 가져올 차례입니다.

다음으로