본문 바로가기
공허의 유산/표현의 자유

[opengl].[#2.GLSL] 17. Texturing 모드

by 바른생활머시마 2023. 2. 11.
728x90
반응형

앞에서 GLSL 기반의 기본적인 Texturing을 살펴 보았습니다.

https://learn-and-give.tistory.com/64

 

[opengl].[#2.GLSL] 16. Texturing 기초

제법 멋진 Spot light까지 쉐이더로 구현 해 보았습니다. https://learn-and-give.tistory.com/63 [opengl].[#2.GLSL] 15. Spot light Directional light를 살펴보다가 Positional light, 즉, 점광원을 살펴봤습니다. https://learn-and-g

learn-and-give.tistory.com

 

이 기본 상태에서는 폴리곤의 색상 대신 텍스쳐 색상이 그대로 표현되기 때문에, 폴리곤에 적용 되었던 조명 효과나 재질의 색상은 전혀 쓰이지 않습니다. 재질의 색상은 텍스쳐 자체에 색감을 적용해서 나타내도 되지만, 조명에 의한 입체감을 나타내기 위해서는 텍스쳐만의 색상으로는 표현을 하기 어렵습니다. 그래서, 텍스쳐링이 될 메쉬의 색상을 어떻게 활용 할 것인가에 대한 옵션이 있습니다.

 

Fixed rendering pipeline에서는 이를 텍스쳐링 옵션 선택으로 처리 가능합니다.

https://learn.microsoft.com/en-us/windows/win32/opengl/gltexenvf

 

glTexEnvf function (Gl.h) - Win32 apps

The glTexEnvf function sets a texture environment parameter.

learn.microsoft.com

 

함수의 파라미터 설명을 보니, 텍스쳐링에 대해서는 고정 파이프라이에서 할 수 있는 것이 별로 없다는 것도 알 수 있네요.

Parameters

target

A texture environment. Must be GL_TEXTURE_ENV.

pname

The symbolic name of a single-valued texture environment parameter. Must be GL_TEXTURE_ENV_MODE.

param

A single symbolic constant, one of GL_MODULATE, GL_DECAL, GL_BLEND, or GL_REPLACE.

 

함수 이름은 텍스쳐 환경 파라미터 설정인데, 설정 할 수 있는 것이 별로 없네요. 아마도 처음 저 함수를 만들 당시에는 여러가지 옵션을 설정 할 수 있도록 확장 할 계획이었을 것 같은데, 그렇게 옵션을 줘서 해결 할 수 있는 것도 한계가 있고 쉐이더라는 기술이 있으니 더 이상 추가가 되지 않을 것 아닐까 추측 해 봅니다. (아무런 근거는 없어요.)

그런데, Extension을 쓰면 좀 더 다양한 옵션 설정이 가능할 것 같아요. 이미 작성했던 코드를 보면 두 가지 옵션을 쓰고 있는데, 위에 없는 옵션도 있어요.

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
	glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);

 

각 모드에 따라 폴리곤의 색상과 텍스쳐의 색상이 섞이는 규칙은 다음과 같습니다.

 

 Fixed pipeline rendering 상태에서 한번 테스트 해 보겠습니다.

먼저 방향광을 설정하고 육면체에 조명 효과가 나오도록 합니다.

 

여기에 텍스쳐링을 다시 적용합니다.

다른 옵션은 다 쓰지 않고, 텍스쳐링을 활성화 하고, 텍스쳐 바인딩만 해줍니다.

void InitTexture()
{
	bool result;
	result = LoadTGA(&textures[0], (char*)("box_tga.tga"));

	GLubyte str[1024];

	/*
	char* extensions;
	extensions = strdup((char*)glGetString(GL_EXTENSIONS));			// Fetch Extension String
	int len = strlen(extensions);
	for (int i = 0; i < len; i++)										// Separate It By Newline Instead Of Blank
		if (extensions[i] == ' ') extensions[i] = '\n';
	printf("%s", extensions);
	*/

	glEnable(GL_TEXTURE_2D);

	// TEXTURE-UNIT #0		
	//glActiveTextureARB(GL_TEXTURE0_ARB);
	glBindTexture(GL_TEXTURE_2D, textures[0].texID);
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
	//glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);


	//glTexEnvf
}

결과는 아래와 같이 파란색 메쉬에 텍스쳐가 적용 된 결과를 볼 수 있습니다.

옵션을 지정하지 않으면 기본값인 MODULATE가 적용되기 때문입니다. 이 옵션을 REPLACE로 하면, 메쉬의 색상은 다 무시하고 텍스쳐의 색상으로 대체가 됩니다. GL_DECAL은 알파 성분에 대한 처리가 달라지는데 Blending 설정도 해야하니 일단 패스하도록 하겠습니다. 

이처럼 텍스쳐링 옵션을 쓸 수 있다는 것을 알았고, 이것을 GLSL로 구변해 보도록 하겠습니다.

 

한가지 생각 해 볼 점으로, 고정 파이프라인 랜더링으로 된다면 왜 그것을 똑같이 구현하는 쉐이더를 써야 하느냐??

목적이 똑같이 쓰는 것이 아닐 수 있기 때문이죠. 그냥 아무것도 없는 상태에서 뭔가를 구상하기는 쉽지 않고, 구현은 더더욱 어렵죠. 그러니, 조명이나 텍스쳐링을 새롭게 해 보고 싶다면, 기존에 구현 된 기술을 바탕에서 어떻게 수정 할 수 있을지 먼저 생각 해 보는 것이 좋을 것 같습니다. 그런 의미에서, 기존의 표현 형태인 고정 파이프라인 바탕의 랜더링 기술을 이해하고, 내가 새롭게 표현하고 싶은 것이 있다면 기존 기술 중 어떤 기술을 바탕으로 개발하면 좋을지 생각해 보는 방향으로 접근하면 보다 빠르고 정확하게 접근 할 수 있을 것 같습니다. 그런 의미에서 이렇게 고정 파이프라인 랜더링 방식을 쉐이더로 구현하는 것을 배운다고 생각 됩니다.

 

 

 

Shader를 이용한 텍스쳐링 모드 구현

 대략의 설명은 앞에서 했으니, 일단 쉐이더 코드부터 한번 살펴보겠습니다.

 

Vertex shader

	varying vec3 lightDir,normal;
	
	void main()
	{
	
		normal = normalize(gl_NormalMatrix * gl_Normal);
		lightDir = normalize(vec3(gl_LightSource[0].position));
		
		gl_TexCoord[0] = gl_MultiTexCoord0;
		gl_Position = ftransform();
	}

Vertex shader를 보면, 특별히 다른 점은 없고, 텍스쳐 좌표가 전달된다는 점만 눈여겨 보도록 하겠습니다.

 

 

Fragment shader

 

Fragment shader는 기존의 재질/조명 관련 코드에서 색상값을 그냥 한번에 설정하는 것이 아니고, 텍스쳐 랜더링 모드에 따라 계산 될 수 있도록 폴리곤의 색상(cf), 폴리곤의 알파(af), 텍스쳐의 색상(ct), 텍스쳐의 알파(at) 각각 분리한 후, 모드에 따라 사용합니다. 아래 코드의 가장 마지막 코드의 vec4 내부의 값 계산 수식은 두 개가 섞이는 것이므로 Modulate 옵션에 해당합니다. 특히 텍스쳐로부터 색상 정보를 얻어오는 sampler2D를 눈여겨 봐야 합니다. texture2D라는 함수를 보면, 어떤 텍스쳐에서 어떤 좌표에 있는 색상을 얻어오는 역할을 한다는 것을 알 수 있습니다.

	varying vec3 lightDir,normal;
	uniform sampler2D tex;
	void main()
	{
		vec3 ct,cf;
		vec4 texel;
		float intensity,at,af;		
		intensity = max(dot(lightDir,normalize(normal)),0.0);
		cf = intensity * (gl_FrontMaterial.diffuse).rgb + 
						  gl_FrontMaterial.ambient.rgb;
		af = gl_FrontMaterial.diffuse.a;
		texel = texture2D(tex,gl_TexCoord[0].st);
		ct = texel.rgb;
		at = texel.a;		
		gl_FragColor = vec4(ct * cf, at * af);	
	}

 

이런 연산의 결과로, 재질의 푸르스름한 색과 텍스쳐 이미지가 섞여서 아래와 같은 결과가 만들어 집니다.

이제 원리에 대한 이해는 어느 정도 되었으니 조금 이쁘게 보이도록 조명과 재질을 좀 더 밝게 수정하겠습니다.

 

이상 GLSL에서 텍스쳐링 옵션을 구현하는 방법을 살펴 보았습니다. 재질과 텍스쳐링 성분을 어떻게 섞을지를 직접 결졍 할 수 있기 때문에 표현 할 수 있는 방법은 무한하죠. 다만, 성능을 고려해야 한다는 점~~~

다음에는 멀티텍스쳐링을 살펴보겠습니다.

https://learn-and-give.tistory.com/66

 

[opengl].[#2.GLSL] 18. MultiTexturing

앞에서 텍스쳐링 모드를 살펴보았습니다. https://learn-and-give.tistory.com/65 [opengl].[#2.GLSL] 17. Texturing 모드 앞에서 GLSL 기반의 기본적인 Texturing을 살펴 보았습니다. https://learn-and-give.tistory.com/64 [opengl].

learn-and-give.tistory.com

 

728x90
반응형

댓글