opengl

opengl 텍스처 겹치기 / 컴파일 쉐이더, 텍스처로드 함수화

현구구 2023. 1. 5. 11:50

 

// sb6.h 헤더 파일을 포함시킨다.
#include <sb7.h>
#include <vmath.h>
#include <shader.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

// sb6::application을 상속받는다.
class my_application : public sb7::application
{
public:
	// 쉐이더 컴파일한다.
	GLuint compile_shader(const char* vs_file, const char* fs_file)
	{
		// 버텍스 쉐이더를 생성하고 컴파일한다.
		GLuint vertex_shader = sb7::shader::load(vs_file, GL_VERTEX_SHADER);

		// 프래그먼트 쉐이더를 생성하고 컴파일한다.
		GLuint fragment_shader = sb7::shader::load(fs_file, GL_FRAGMENT_SHADER);

		// 프로그램을 생성하고 쉐이더를 Attach시키고 링크한다.
		GLuint program = glCreateProgram();
		glAttachShader(program, vertex_shader);
		glAttachShader(program, fragment_shader);
		glLinkProgram(program);

		// 이제 프로그램이 쉐이더를 소유하므로 쉐이더를 삭제한다.
		glDeleteShader(vertex_shader);
		glDeleteShader(fragment_shader);

		return program;
	}

	void load_texture(GLuint texture, const char* filename)
	{
		// 텍스처 객체 만들고 바인딩			
		glBindTexture(GL_TEXTURE_2D, texture);

		// 텍스처 이미지 로드하기
		int width, height, nrChannels;
		unsigned char* data = stbi_load(filename, &width, &height, &nrChannels, 0);

		if (data) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data);

		// 텍스처 샘플링/필터링 설정
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}

	// 애플리케이션 초기화 수행한다.
	virtual void startup()
	{
		// 쉐이더 프로그램 컴파일 및 연결
		shader_programs[0] = compile_shader("texture_vs.glsl", "texture_fs.glsl");

		// VAO, VBO, EBO, texture 생성
		glGenVertexArrays(2, VAOs); //하나일때는 &참조기호 넣어줘야함
		glGenBuffers(2, VBOs);
		glGenTextures(7, textures);
		//--------------------------------------------------
		glGenTextures(1, &texture2);
		glBindTexture(GL_TEXTURE_2D, texture2);
		int width5, height5, nrChannels5;
		unsigned char* data5 = stbi_load("container.jpg", &width5, &height5, &nrChannels5, 0);

		if (data5) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width5, height5, 0, GL_RGB, GL_UNSIGNED_BYTE, data5);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data5);

		// 텍스처 샘플링/필터링 설정
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

		
		// 박스 --------------------------------------------------
		glBindVertexArray(VAOs[1]);
		// 박스 점들의 위치와 컬러, 텍스처 좌표를 정의한다.
		float box_s = 1.0f, box_t = 1.0f;
		GLfloat box_vertices[] = {
			// 뒷면
			-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, box_t,
			0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
			-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, 0.0f,

			0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
			-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, box_s, box_t,
			0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 0.0f, 0.0f, box_t,
			// 우측면
			0.25f, 0.0f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, 0.0f,
			0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, box_t,
			0.25f, 0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,

			0.25f, 0.0f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
			0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 0.0f, box_s, box_t,
			0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 0.0f, 0.0f, box_t,
			// 정면
			0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, 0.0f,
			0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, box_t,
			-0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

			-0.25f, 0.0f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
			0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, box_s, box_t,
			-0.25f, 0.5f, 0.25f, 0.0f, 0.0f, 1.0f, 0.0f, box_t,
			// 좌측면
			-0.25f, 0.0f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, 0.0f,
			-0.25f, 0.5f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, box_t,
			-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,

			-0.25f, 0.0f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,
			-0.25f, 0.5f, 0.25f, 1.0f, 0.0f, 1.0f, box_s, box_t,
			-0.25f, 0.5f, -0.25f, 1.0f, 0.0f, 1.0f, 0.0f, box_t,
			// 바닥면
			-0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, box_s, 0.0f,
			0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, 0.0f, box_t,
			0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f,

			0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, 0.0f, box_t,
			-0.25f, 0.0f, 0.25f, 1.0f, 1.0f, 0.0f, box_s, 0.0,
			-0.25f, 0.0f, -0.25f, 1.0f, 1.0f, 0.0f, box_s, box_t,
			// 윗면
			-0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 0.0f, box_t,
			0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, box_s, 0.0f,
			0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, box_s, box_t,

			0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, box_s, 0.0f,
			-0.25f, 0.5f, -0.25f, 0.0f, 1.0f, 1.0f, 0.0f, box_t,
			-0.25f, 0.5f, 0.25f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f
		};

		// VBO를 생성하여 vertices 값들을 복사
		glBindBuffer(GL_ARRAY_BUFFER, VBOs[1]);
		glBufferData(GL_ARRAY_BUFFER, sizeof(box_vertices), box_vertices, GL_STATIC_DRAW);

		// VBO를 나누어서 각 버텍스 속성으로 연결
		// 위치 속성 (location = 0)
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
		glEnableVertexAttribArray(0);
		// 컬러 속성 (location = 1)
		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
		glEnableVertexAttribArray(1);
		// 텍스처 좌표 속성 (location = 2)
		glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
		glEnableVertexAttribArray(2);

		// VBO 및 버텍스 속성을 다 했으니 VBO와 VAO를 unbind한다.
		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glBindVertexArray(0);


		// 텍스처 로드 --------------------------------------------------
		stbi_set_flip_vertically_on_load(true);
		load_texture(textures[1], "side1.png");
		load_texture(textures[2], "side2.png");
		load_texture(textures[3], "side3.png");
		load_texture(textures[4], "side4.png");
		load_texture(textures[5], "side5.png");
		load_texture(textures[6], "side6.png");

	}

	// 애플리케이션 끝날 때 호출된다.
	virtual void shutdown()
	{
		glDeleteTextures(7, textures);
		glDeleteBuffers(2, VBOs);
		glDeleteVertexArrays(2, VAOs);
		glDeleteProgram(shader_programs[0]);
	}

	// 렌더링 virtual 함수를 작성해서 오버라이딩한다.
	virtual void render(double currentTime)
	{
		const GLfloat black[] = { 0.0f, 0.0f, 0.0f, 1.0f };
		glClearBufferfv(GL_COLOR, 0, black);
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);

		GLint uniform_transform1 = glGetUniformLocation(shader_programs[0], "transform");

		// 카메라 매트릭스 계산
		float distance = 2.f;
		vmath::vec3 eye((float)cos(currentTime * 0.1f) * distance, 0.7, (float)sin(currentTime * 0.1f) * distance);
		vmath::vec3 center(0.0, 0.0, 0.0);
		vmath::vec3 up(0.0, 1.0, 0.0);
		vmath::mat4 lookAt = vmath::lookat(eye, center, up);
		float fov = 50.f;
		vmath::mat4 projM = vmath::perspective(fov, info.windowWidth / (float)info.windowHeight, 0.1f, 1000.0f);
		// 박스 그리기 ---------------------------------------
		vmath::mat4 transM = vmath::translate(0.0f, 0.5f, 0.0f);
		vmath::mat4 scaleM = vmath::scale((float)sin(currentTime) * 0.25f + 0.75f);
		float angle = currentTime * 100;
		vmath::mat4 rotateY = vmath::rotate(angle, 0.0f, 1.0f, 0.0f);
		vmath::mat4 rotateX = vmath::rotate(angle * 0.5f, 1.0f, 0.0f, 0.0f);

		glUseProgram(shader_programs[0]);
		glBindVertexArray(VAOs[1]);
		glUniformMatrix4fv(uniform_transform1, 1, GL_FALSE, projM * lookAt * transM * rotateX * rotateY * vmath::translate(0.f, -0.25f, 0.f));
		for (int i = 0; i < 6; i++)
		{
			glUniform1i(glGetUniformLocation(shader_programs[0], "texture1"), 0);
			glActiveTexture(GL_TEXTURE0);
			glBindTexture(GL_TEXTURE_2D, textures[i + 1]);
			glDrawArrays(GL_TRIANGLES, 6 * i, 6);
		}
		glUniform1i(glGetUniformLocation(shader_programs[0], "texture2"), 1);
		glActiveTexture(GL_TEXTURE1);
		glBindTexture(GL_TEXTURE_2D, texture2);
		glDrawArrays(GL_TRIANGLES, 0, 36);
	}

private:
	GLuint shader_programs[2];
	GLuint VAOs[2], VBOs[2], EBOs[1];
	GLuint textures[7];
	GLuint texture2;
};

// DECLARE_MAIN의 하나뿐인 인스턴스
DECLARE_MAIN(my_application)

컴파일 함수 구현

인자로 버텍스 쉐이더 파일과 프래그먼트 쉐이더 파일이 들어간다.

텍스처 로드 함수 구현

인자로는 바인딩할 텍스처 객체와 .png 텍스처 파일이 필요하다.

 

구현한 함수들은 startup에서 사용한다.

변수들을 미리 선언하고 구현한 함수를 사용한다.

//<<<texture_vs.glsl>>>
#version 430 core											
															
layout(location = 0) in vec3 pos;							
layout(location = 1) in vec3 color;						
layout(location = 2) in vec2 texCoord;						
															
uniform mat4 transform;									
															
out vec3 vsColor;											
out vec2 vsTexCoord;										
															
void main(void)											
{															
	gl_Position = transform*vec4(pos.x, pos.y, pos.z, 1.0);	
															
	vsColor = color;										
	vsTexCoord = texCoord;									
}

위치, 색상, 텍스처를 가져오고

위치는 버텍스 쉐이더에서 처리

색상과 텍스처는 out을 통해 프래그먼트 쉐이더로 보낸다.

//<<<texture_fs.glsl>>>
#version 430 core								
												
in vec3 vsColor;								
in vec2 vsTexCoord;							
uniform sampler2D texture1;	
uniform sampler2D texture2;				
												
out vec4 fragColor;							
												
void main(void)								
{	
	vec4 color = vec4(texture(texture1, vsTexCoord));					
	if(color.x>=0.3&&color.y>=0.3&&color.z>=0.3)
	{
		fragColor = texture(texture2, vsTexCoord);
	}
	else
	{
		fragColor = texture(texture1, vsTexCoord);
	}
}

가져온 텍스처와 색상을 처리한다.(여기서는 색상을 다루지 않음)

texture1에는 주사위의 각 면 1,2,3,4,5,6이,

texture2에는 박스 텍스처가 들어가있다.

 

먼저 color 벡터에 1, 2, 3, 4, 5, 6 주사위의 각 면 텍스처를 저장하고

r,g,b 모든 값이 0.3(임의로정함)보다 크다면 (주사위의 바탕은 흰색 r,g,b가 1에 가까울 것) 해당 곳에는 texture2를 그려준다.

 

 

'opengl' 카테고리의 다른 글

opengl spot,point 라이팅  (0) 2023.01.05
opengl 라이팅 Phong모델  (0) 2023.01.05
opengl 텍스처  (0) 2023.01.04
opengl 시점변환 원근투영 - opengl라이브러리  (0) 2022.09.06
opengl 시점변환 원근투영 - 하드코딩  (0) 2022.09.06