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

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

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

앞에서 텍스쳐링 모드를 살펴보았습니다.

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

 

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

앞에서 GLSL 기반의 기본적인 Texturing을 살펴 보았습니다. https://learn-and-give.tistory.com/64 [opengl].[#2.GLSL] 16. Texturing 기초 제법 멋진 Spot light까지 쉐이더로 구현 해 보았습니다. https://learn-and-give.tistory.

learn-and-give.tistory.com

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

멀티 텍스쳐링은 말 그대로 여러 개의 텍스쳐를 사용하는 것인데, 이 내용을 이해하면 훨씬 다양한 표현을 할 수 있게 됩니다 텍스쳐가 겉으로 보여지는 이미지 정보를 담는 역할에 머물지 않고, 또 다른 정보를 전달하는 데이터로써 역할을 할 수 있습니다. 3D 콘텐츠 관련 된 경험이 있다면, Normal map이라는 말을 들어보신 적이 있을텐데, 이 Normal map이라는 것은 텍스쳐와 같이 이미지 데이터인데, 그 데이터가 겉에 입혀질 데이터가 아니라 각 픽셀별 노멀 정보를 담고 있는 이미지 입니다. 법선의 방향이 XYZ 세 방향인데, 공교롭게도(?) 색상도 RGB 세 성분이라서, 방향을 나타내는 성분 3개를 색상처럼 표현 할 수 있습니다. 그래서, 실제로 담고 있는 정보는 법선 정보인데, 보편적으로 많이 쓰이는 이미지 형태로 이를 전달 할 수 있습니다.

 

아래 이미지는 Unity 관련 자료에 포함 된 이미지인데요. 왼쪽의 이미지는 일반적인 텍스쳐이고, 오른쪽은 노멀맵 텍스쳐입니다. 즉, 텍스쳐 데이터 형태로 어떤 자료가 전달되면 이를 필요한 효과를 내기 위한 계산에 쓸 수 있습니다. Normal map을 써서 울퉁불퉁한 효과를 내는 bump mapping은 다음에(?) 살펴보고, 두 장의 이미지를 단순히 섞어서 그려주는 샘플을 살펴 보겠습니다.

 

 

Multi-Texturing

먼저 Multi texturing이 무엇인지 정리를 한번 하자면,  하나의 픽셀에 사용 할 수 있는 텍스쳐가 여러 개라는 뜻이지, 단순히 사용하는 텍스쳐 개수가 여러개라는 뜻은 아닙니다. 

 

 예를 들어 주사위의 각 면을 별도의 이미지로 표현 한다고 할 경우, 사용되는 이미지는 총 6개 입니다. 이때, 면 하나를 그릴때는 하나의 이미지만 사용합니다. OpenGL 코드로 설명을 하자면, 각 면의 폴리곤을 그릴 때, 그 면에 해당하는 텍스쳐를 Binding 해줍니다. 텍스쳐 바인딩 명령인 glBindTexture는 한 번에 하나만 할 수 있습니다. 

 

 반면 멀티 텍스쳐를 하나의 폴리곤을 그릴 때 여러 개의 텍스쳐를 사용하는 것입니다. 주사위의 예를 들면, 여러가지 재질의 주사위를 그리는 경우를 가정 해 보겠습니다.

  나무 주사위와 돌맹이 주사위를 만든다고 할때, 멀티텍스쳐를 쓰지 않는다면, 각 재질별로 6개의 눈이 그려진 텍스쳐 이미지를 만들어야 합니다.(물론 하나의 큰 이미지로 한장 만들어도 되지만, 설명을 위해 하나의 면에 각각 이미지를 쓴다고 가정하고...), 그러나, 멀티 텍스쳐링을 쓰면, 눈 이미지 6장과 재질 이미지 2장을 이용해서 그 조합(동시에 사용되는 텍스쳐의 조합)으로 그려 낼 수 있습니다. 또한, 재질이 추가되면 그 재질 텍스쳐 이미지 1장만 추가하면 재질별 주사위를 계속 만들어 낼 수 있습니다. 이때 이 "동시에 텍스쳐의 조합"을 쓸 수 있게 해주는 기술이 바로 멀티 텍스쳐링에 해당합니다.

 

 이 부분을 이해하지 못하면 동시에 두 개의 텍스쳐를 사용하는 방법을 이해하기 어렵기 때문에 꼭 이 부분 먼저 생각해야 합니다.  또한, 이 기능들은 OpenGL 버젼에 따라 지원 될 수도 있고, Extension으로 지원 될 수도 있기 때문에 버젼에 대한 고려도 필요합니다.(옛날에 그랬으니 최근 버젼에는 아마 기본 기능이 아닐까 싶네요.) 앞서 텍스쳐를 읽을 때 extension 지원 여부를 확인하는 코드가 주석처리되어 포함되어 있었는데, 멀티텍스쳐링 지원 여부를 확인하기 위해서 이 부분에 있었던 것입니다.

 

 

glActiveTexture

 

 중요하게 봐야 할 새로운 함수가 바로, glActiveTexture 함수 입니다. 이것이 바로 동시에 사용 될 텍스쳐 중 어떤 것에 대한 코드가 이어 질 것인가에 대한 설정을 해주는 것입니다. Bind texture의 역할과 비슷한데, Bind texture 상위의 Binding으로 이해하면 좋겠습니다. glActiveTexture로 활성화 시킨 텍스쳐0, 1, 2 그 안에서도 각각 텍스쳐들이 texture id를 이용해서 binding 되게 됩니다. 이것을 제대로 이해하지 못하는 경우가 꽤 많은지, 저도 한참 고생하다가 흔한 실수 관련 자료에서 답을 찾았습니다.(몇년전에 그랬으니 요즘 환경은 좀 달라졌는지 모르겠네요.)

http://www.opengl.org/wiki/GLSL_:_common_mistakes

 

GLSL : common mistakes - OpenGL Wiki

The following article discusses common mistakes made in the OpenGL Shading Language, GLSL. Uniforms How to use glUniform If you look at all the glUniform*v functions, there is a parameter called count. What's wrong with this code? Would it cause a crash? /

www.khronos.org

중요한 내용은 아래와 같습니다.

 

Binding A Texture

When you compile and link your GLSL shader, the next step is to get uniform locations for your samplers (I'm talking about texture samplers) and setup the samplers. Some people do this:

 

glUniform1i(location, textureID)

 

You can't send a GL texture ID as your sampler. A sampler should be from 0 to the max number of texture image units. Once you compile and link your shader, make sure that you setup all the samplers by calling (assuming of course your samplers are named Texture0, Texture1 and Texture2)

 

location=glGetUniformLocation(shaderProgram, "Texture0");

glUniform1i(location, 0);

location=glGetUniformLocation(shaderProgram, "Texture1");

glUniform1i(location, 1);

location=glGetUniformLocation(shaderProgram, "Texture2");

glUniform1i(location, 2);

 

To bind a texture, always use glBindTexture.

 

glActiveTexture(GL_TEXTURE0);

glBindTexture(GL_TEXTURE_2D, textureID[0]);

glActiveTexture(GL_TEXTURE1);

glBindTexture(GL_TEXTURE_2D, textureID[1]);

glActiveTexture(GL_TEXTURE2);

glBindTexture(GL_TEXTURE_2D, textureID[2]);

 

Alternatively:

for(i=0; i<3; i++)

{

  glActiveTexture(GL_TEXTURE0+i);

  glBindTexture(GL_TEXTURE_2D, textureID[i]);

}

 

If you don't set the samplers properly, you might get a link failure that says something to the effect of:

Output from shader Fragment shader(s) linked, vertex shader(s) linked.

Validation failed - samplers of different types are bound to the same texture image unit.

 

 

자, 대충 관련 설명은 이 정도로 하고 이제 코드를 살펴보겠습니다.

초기화

텍스쳐 관련 초기화 코드를 먼저 살펴보겠습니다. 코드를 보면서 설명을 이어 나가도록 하겠습니다.

void InitTexture()
{
	bool result;
	result = LoadTGA(&textures[0], (char*)("box_tga.tga"));
	result = LoadTGA(&textures[1], (char*)("l3d_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);
	*/

	// TEXTURE-UNIT #0		
	glActiveTextureARB(GL_TEXTURE0_ARB);
	glEnable(GL_TEXTURE_2D);
	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);
	// TEXTURE-UNIT #1:
	glActiveTextureARB(GL_TEXTURE1_ARB);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, textures[1].texID);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
	glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_ADD);

	glActiveTexture(GL_TEXTURE0_ARB);
	glBindTexture(GL_TEXTURE_2D, textures[0].texID);
	glActiveTexture(GL_TEXTURE1_ARB);
	glBindTexture(GL_TEXTURE_2D, textures[1].texID);
}

 

그리고, 몇번 텍스쳐인지에 대한 정보를 uniform 변수로 전달해야 합니다.

	loc = glGetUniformLocation(program_shader, "tex");
	glUniform1i(loc, 0);
	loc = glGetUniformLocation(program_shader, "l3d");
	glUniform1i(loc, 1);

tex라는 텍스쳐는 0번, l3d라는 텍스쳐는 1번을 사용합니다.

 

이미지 데이터는 전달하지 코드가 보이지 않는데 괜찮을까요??

텍스쳐는 이전부터 이미 GPU쪽으로 데이터를 다 등록을 해 놓고 ID를 받아오는 방식으로 이전부터 사용되고 있었습니다. 

LoadTGA 함수 내부를 살펴보면 아래와 같은 코드가 있습니다.

	// Build A Texture From The Data
	glGenTextures(1, &(texture->texID));					// Generate OpenGL texture IDs

	glBindTexture(GL_TEXTURE_2D, texture->texID);				// Bind Our Texture
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);	// Linear Filtered
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);	// Linear Filtered

	if (texture[0].bpp == 24)							// Was The TGA 24 Bits
	{
		type = GL_RGB;							// If So Set The 'type' To GL_RGB
	}

	glTexImage2D(GL_TEXTURE_2D, 0, type, texture[0].width, texture[0].height, 0, type, GL_UNSIGNED_BYTE, texture[0].imageData);

먼저 GPU에 텍스쳐 저장 공간을 할당 받아서 ID를 전달 받고, glTexImage2D라는 함수를 통해서 이미지 데이터를 GPU로 전달하는 과정을 거치게 됩니다. 그렇기 때문에, 이미지 데이터를 uniform으로 전달 할 필요는 없습니다.

 

육면체를 그려주는 코드도 멀티 텍스쳐링이 되도록 수정하겠습니다.

void	DrawMultiTexCube()
{
	glBegin(GL_TRIANGLES);
	//+Z
		glNormal3f(0.f,0.f,1.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c0);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c1);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c2);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c0);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c2);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c3);
	//-Z
		glNormal3f(0.f,0.f,-1.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c5);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c4);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c7);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c5);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c7);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c6);
	//+X
		glNormal3f(1.f,0.f,0.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c1);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c5);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c6);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c1);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c6);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c2);
	//-X
		glNormal3f(-1.f,0.f,0.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c7);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c4);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c0);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c3);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c7);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c0);
	//+Y
		glNormal3f(0.f,1.f,0.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c2);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c6);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c7);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c2);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c7);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c3);
	//-Y
		glNormal3f(0.f,-1.f,0.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c5);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t2);		glVertex3fv(c1);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c0);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t0);		glVertex3fv(c4);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t1);		glVertex3fv(c5);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t3);		glVertex3fv(c0);

	glEnd();
}

하나의 Vertex에 두 개의 텍스쳐 좌표가 할당 된 것을 볼 수 있습니다.

 

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();
}

Fragment Shader

varying vec3 lightDir,normal;
uniform sampler2D tex,l3d;

void main()
{
	vec3 ct,cf,c;
	vec4 texel;
	float intensity,at,af,a;
	
	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;
	
	c = cf * ct;
	a = af * at;
		
	//float coef = smoothstep(1.0,0.2,intensity);
	//c += coef *  vec3(texture2D(l3d,gl_TexCoord[0].st));
	c += vec3(texture2D(l3d,gl_TexCoord[0].st));
	
	gl_FragColor = vec4(c, a);	
}

이렇게 하면 아래와 같이 두 개의 텍스쳐가 섞여서 나옵니다.

이 경우, 텍스쳐는 두 개를 사용했지만, 텍스쳐 좌표는 gl_TexCoord[0]만 쓰고 있는데 같은 좌표를 써도 되는 경우라서 문제가 없습니다. 그런데, 글자를 더 크게 혹은 더 작게 그려야 한다면 글자를 그리는 텍스쳐의 좌표는 조정이 필요합니다.

 

글자의 텍스쳐 좌표를 두배로 곱하여 새로운 텍스쳐 좌표 배열을 만듭니다. 정상적으로 작동한다면 글자가 절반 크기로 줄어들 것 입니다.

float t0[2] = { 0.f,0.f };
float t1[2] = { 1.f,0.f };
float t2[2] = { 1.f,1.f };
float t3[2] = { 0.f,1.f };


float t20[2] = { 0.f,0.f };
float t21[2] = { 2.0f,0.f };
float t22[2] = { 2.0f,2.0f };
float t23[2] = { 0.f,2.0f };

새로 추가한 변수를 사용하도록 랜더링 코드도 수정합니다.

...
		glNormal3f(0.f,0.f,1.f);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t20);		glVertex3fv(c0);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t1);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t21);		glVertex3fv(c1);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t22);		glVertex3fv(c2);

		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t0);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t20);		glVertex3fv(c0);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t2);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t22);		glVertex3fv(c2);
		glMultiTexCoord2fvARB(GL_TEXTURE0_ARB, t3);		glMultiTexCoord2fvARB(GL_TEXTURE1_ARB, t23);		glVertex3fv(c3);
...

 

Vertex Shader

단순히 두 개의 Vertex 좌표를 전달 해 주도록 한 줄 추가 합니다.

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_TexCoord[1] = gl_MultiTexCoord1;

	gl_Position = ftransform();
}

 

Fragment shader

Fragment shader 역시, 글자 텍스쳐를 참조하는 샘플러에서 참조하는 텍스쳐 좌표를 gl_TexCoord[1]으로 변경해주면 됩니다.

varying vec3 lightDir,normal;
uniform sampler2D tex,l3d;

void main()
{
	vec3 ct,cf,c;
	vec4 texel;
	float intensity,at,af,a;
	
	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;
	
	c = cf * ct;
	a = af * at;
		
	float coef = smoothstep(1.0,0.2,intensity);
	//c += coef *  vec3(texture2D(l3d,gl_TexCoord[0].st));
	c += vec3(texture2D(l3d,gl_TexCoord[1].st));
	
	gl_FragColor = vec4(c, a);	
}

 

결과는!

멋지게 마무리 되었네요.!

 

이것으로 GLSL 리뷰를 마치겠습니다.

Bump mapping도 이 환경에서 어렵지 않게 구현 할 수 있습니다. 즉, 조명에 대한 계산을 할 때 gl_Normal로 전달 된 법선 값을 쓰지 않고, Normal map으로 전달 된 값을 사용하면 각 픽셀마다 법선을 다르게 적용하여 매우 정교한 형상의 느낌을 표현 할 수 있습니다. 그런데, 이런 콘솔 환경에서 구현하는 것은 이론적인 이해에는 도움이 되지만 요즘 이런 환경의 개발 환경이 별로 없으니, Unity에서 Shader 구현하는 것을 공부 해 나가볼까 싶네요.

 

 예전에 작성 해 둔 자료를 정리할 겸 다시 리뷰해 보았는데, 요즘 환경과 너무 동떨어진 내용인 것 같습니다. 그러나, 그래픽스 이론을 공부 할때는 GLSL을 공부하는 것이 매우 도움이 되는 것 같아요.^^

728x90
반응형

댓글