opengl

opengl 텍스처

현구구 2023. 1. 4. 14:58

 


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

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

// sb6::application을 상속받는다.
class my_application : public sb7::application
{
public:
	// 쉐이더 컴파일한다.
	GLuint compile_shaders(void)
	{
		GLuint vertex_shader;
		GLuint fragment_shader;
		GLuint program;

		// 버텍스 쉐이더 소스 코드
		static const GLchar* vertex_shader_source[] =
		{
			"#version 430 core											\n"
			"															\n"
			"layout(location = 0) in vec3 pos;							\n"
			"layout(location = 1) in vec3 color;						\n"
			"layout(location = 2) in vec2 texCoord;						\n"
			"															\n"
			"uniform mat4 rotMat;										\n"
			"															\n"
			"out vec3 vsColor;											\n"
			"out vec2 vsTexCoord;										\n"
			"															\n"
			"void main(void)											\n"
			"{															\n"
			"	gl_Position = rotMat*vec4(pos.x, pos.y, pos.z, 1.0);	\n"
			"															\n"
			"	vsColor = color;										\n"
			"	vsTexCoord = texCoord;									\n"
			"}															\n"
		};

		// 프래그먼트 쉐이더 소스 코드
		static const GLchar* fragment_shader_source[] =
		{
			"#version 430 core						\n"
			"										\n"
			"in vec3 vsColor;						\n"
			"in vec2 vsTexCoord;							\n"
			"uniform sampler2D texture1;					\n"
			"out vec4 fragColor;					\n"
			"										\n"
			"void main(void)						\n"
			"{										\n"

			"	fragColor = texture(texture1, vsTexCoord);	\n"
			"}										\n"
		};

		// 버텍스 쉐이더를 생성하고 컴파일한다.
		vertex_shader = glCreateShader(GL_VERTEX_SHADER);
		glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
		glCompileShader(vertex_shader);

		// 프래그먼트 쉐이더를 생성하고 컴파일한다.
		fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
		glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
		glCompileShader(fragment_shader);

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

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

		return program;
	}
	

	// 애플리케이션 초기화 수행한다.
	virtual void startup()
	{
		rendering_program = compile_shaders();
		glGenVertexArrays(1, &VAO);
		glBindVertexArray(VAO);

		// 박스 점들의 위치와 컬러를 정의한다.
		//삼각형이 12개 필요함
		GLfloat vertices[] = {
			//맨 앞 사각형
			-0.25f, 0.25f, -0.25f, 1.0f, 0.0f, 0.0f,0.0f,1.0f,
			0.25f, -0.25f, -0.25f, 1.0f, 0.0f, 0.0f,1.0f,0.0f,
			-0.25f, -0.25f, -0.25f, 1.0f, 0.0f, 0.0f,0.0f,0.0f,

			0.25f, -0.25f, -0.25f, 1.0f, 0.0f, 0.0f,1.0f,0.0f,
			-0.25f, 0.25f, -0.25f, 1.0f, 0.0f, 0.0f,0.0f,1.0f,
			0.25f, 0.25f, -0.25f, 1.0f, 0.0f, 0.0f,1.0f,1.0f,
			//왼쪽 측면 사각형
			0.25f, -0.25f, -0.25f, 0.0f, 1.0f, 0.0f,0.0f,0.0f,
			0.25f, 0.25f, -0.25f, 0.0f, 1.0f, 0.0f,0.0f,1.0f,
			0.25f, -0.25f, 0.25f, 0.0f, 1.0f, 0.0f,1.0f,0.0f,

			0.25f, -0.25f, 0.25f, 0.0f, 1.0f, 0.0f,1.0f,0.0f,
			0.25f, 0.25f, -0.25f, 0.0f, 1.0f, 0.0f,0.0f,1.0f,
			0.25f, 0.25f, 0.25f, 0.0f, 1.0f, 0.0f,1.0f,1.0f,
			//뒤에 사각형
			0.25f, -0.25f, 0.25f, 0.0f, 0.0f, 1.0f,0.0f,0.0f,
			0.25f, 0.25f, 0.25f, 0.0f, 0.0f, 1.0f,0.0f,1.0f,
			-0.25f, -0.25f, 0.25f, 0.0f, 0.0f, 1.0f,1.0f,0.0f,

			-0.25f, -0.25f, 0.25f, 0.0f, 0.0f, 1.0f,1.0f,0.0f,
			0.25f, 0.25f, 0.25f, 0.0f, 0.0f, 1.0f,0.0f,1.0f,
			-0.25f, 0.25f, 0.25f, 0.0f, 0.0f, 1.0f,1.0f,1.0f,
			//오른쪽 측면 사각형
			-0.25f, -0.25f, 0.25f, 1.0f, 0.0f, 1.0f,0.0f,0.0f,
			-0.25f, 0.25f, 0.25f, 1.0f, 0.0f, 1.0f,0.0f,1.0f,
			-0.25f, -0.25f, -0.25f, 1.0f, 0.0f, 1.0f,1.0f,0.0f,

			-0.25f, -0.25f, -0.25f, 1.0f, 0.0f, 1.0f,1.0f,0.0f,
			-0.25f, 0.25f, 0.25f, 1.0f, 0.0f, 1.0f,0.0f,1.0f,
			-0.25f, 0.25f, -0.25f, 1.0f, 0.0f, 1.0f,1.0f,1.0f,
			//아래 사각형
			-0.25f, -0.25f, 0.25f, 1.0f, 1.0f, 0.0f,0.0f,1.0f,
			0.25f, -0.25f, -0.25f, 1.0f, 1.0f, 0.0f,1.0f,0.0f,
			0.25f, -0.25f, 0.25f, 1.0f, 1.0f, 0.0f,0.0f,0.0f,

			0.25f, -0.25f, -0.25f, 1.0f, 1.0f, 0.0f,1.0f,0.0f,
			-0.25f, -0.25f, 0.25f, 1.0f, 1.0f, 0.0f,0.0f,1.0f,
			-0.25f, -0.25f, -0.25f, 1.0f, 1.0f, 0.0f,1.0f,1.0f,
			//위에 사각형
			-0.25f, 0.25f, -0.25f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
			0.25f, 0.25f, 0.25f, 0.0f, 1.0f, 1.0f,1.0f,0.0f,
			0.25f, 0.25f, -0.25f, 0.0f, 1.0f, 1.0f,0.0f,0.0f,

			0.25f, 0.25f, 0.25f, 0.0f, 1.0f, 1.0f,1.0f,0.0f,
			-0.25f, 0.25f, -0.25f, 0.0f, 1.0f, 1.0f,0.0f,1.0f,
			-0.25f, 0.25f, 0.25f, 0.0f, 1.0f, 1.0f,1.0f,1.0f
		};

		// VBO를 생성하여 vertices 값들을 복사
		glGenBuffers(1, &VBO);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), 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);

		//---텍스트 처리
		glGenTextures(1, &texture1);
		glBindTexture(GL_TEXTURE_2D, texture1);

		// 텍스처 이미지 로드하기
		int width1, height1, nrChannels1;
		unsigned char* data1 = stbi_load("side1.png", &width1, &height1, &nrChannels1, 0);

		if (data1) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width1, height1, 0, GL_RGB, GL_UNSIGNED_BYTE, data1);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data1);

		// 텍스처 샘플링/필터링 설정
		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);
		//----------
		glGenTextures(1, &texture2);
		glBindTexture(GL_TEXTURE_2D, texture2);

		// 텍스처 이미지 로드하기
		int width2, height2, nrChannels2;
		unsigned char* data2 = stbi_load("side2.png", &width2, &height2, &nrChannels2, 0);

		if (data2) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width2, height2, 0, GL_RGB, GL_UNSIGNED_BYTE, data2);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data2);
		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);
		//----------------------------
		glGenTextures(1, &texture3);
		glBindTexture(GL_TEXTURE_2D, texture3);

		// 텍스처 이미지 로드하기
		int width3, height3, nrChannels3;
		unsigned char* data3 = stbi_load("side3.png", &width3, &height3, &nrChannels3, 0);

		if (data3) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width3, height3, 0, GL_RGB, GL_UNSIGNED_BYTE, data3);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data3);
		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);
		//------------------
		glGenTextures(1, &texture4);
		glBindTexture(GL_TEXTURE_2D, texture4);

		// 텍스처 이미지 로드하기
		int width4, height4, nrChannels4;
		unsigned char* data4 = stbi_load("side4.png", &width4, &height4, &nrChannels4, 0);

		if (data4) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width4, height4, 0, GL_RGB, GL_UNSIGNED_BYTE, data4);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data4);

		// 텍스처 샘플링/필터링 설정
		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);
		//------------------------
		glGenTextures(1, &texture5);
		glBindTexture(GL_TEXTURE_2D, texture5);

		// 텍스처 이미지 로드하기
		int width5, height5, nrChannels5;
		unsigned char* data5 = stbi_load("side5.png", &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);
		//--------------------------
		glGenTextures(1, &texture6);
		glBindTexture(GL_TEXTURE_2D, texture6);

		// 텍스처 이미지 로드하기
		int width6, height6, nrChannels6;
		unsigned char* data6 = stbi_load("side6.png", &width6, &height6, &nrChannels6, 0);

		if (data6) {
			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width6, height6, 0, GL_RGB, GL_UNSIGNED_BYTE, data6);
			glGenerateMipmap(GL_TEXTURE_2D);
		}
		stbi_image_free(data6);

		// 텍스처 샘플링/필터링 설정
		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 shutdown()
	{
		glDeleteVertexArrays(1, &VAO);
		glDeleteProgram(rendering_program);
	}

	// 렌더링 virtual 함수를 작성해서 오버라이딩한다.
	virtual void render(double currentTime)
	{
		const GLfloat color[] = { (float)sin(currentTime) * 0.5f + 0.5f, (float)cos(currentTime) * 0.5f + 0.5f, 0.0f, 1.0f };
		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);// 정육면체처럼 보이게 해주는 함수
		//=========================박스========================

		// 렌더링위해 생성한 프로그램 객체를 사용하도록 한다.
		glUseProgram(rendering_program);

		vmath::mat4 transM = vmath::translate(vmath::vec3(0.0f, 0.8f, 0.0f));
		float angle = currentTime * 100;
		vmath::mat4 rotateM = vmath::rotate(angle, 0.0f, 1.0f, 0.0f);
		vmath::mat4 rotateM10 = vmath::rotate(angle, 1.0f, 0.0f, 0.0f);
		vmath::mat4 rotateM11 = vmath::rotate(angle, 0.0f, 0.0f, 1.0f);
		vmath::vec3 eye(0.0, 1.5, -4.0);
		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);
		//원근투영 배열 세로방향 시야 각도(고정아면 양옆으로 움직임), 화면 가로 나누기 세로, 가까이 있는 화면, 멀리있는 화면
		vmath::mat4 projM = vmath::perspective(35.0f, info.windowWidth / info.windowHeight, 0.1f, 1000.0f);

		// "rotMat" uniform에 대한 위치를 가져온다.
		GLint rotMatLocation = glGetUniformLocation(rendering_program, "rotMat");
		// "rotMat" uniform으로 전달한다.
		glUniformMatrix4fv(rotMatLocation, 1, GL_FALSE, projM * lookAt * transM * rotateM * rotateM10 * rotateM11);

		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 5);
		glActiveTexture(GL_TEXTURE5);
		glBindTexture(GL_TEXTURE_2D, texture1);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 6);

		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 6);
		glActiveTexture(GL_TEXTURE6);
		glBindTexture(GL_TEXTURE_2D, texture2);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 6, 6);


		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 7);
		glActiveTexture(GL_TEXTURE7);
		glBindTexture(GL_TEXTURE_2D, texture3);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 12, 6);

		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 8);
		glActiveTexture(GL_TEXTURE8);
		glBindTexture(GL_TEXTURE_2D, texture4);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 18, 6);

		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 9);
		glActiveTexture(GL_TEXTURE9);
		glBindTexture(GL_TEXTURE_2D, texture5);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 24, 6);

		glUniform1i(glGetUniformLocation(rendering_program, "texture1"), 10);
		glActiveTexture(GL_TEXTURE10);
		glBindTexture(GL_TEXTURE_2D, texture6);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 30, 6);
	}

private:
	GLuint rendering_program;
	GLuint VAO, VBO;
	GLuint EBO;
	GLuint texture1, texture2, texture3, texture4, texture5, texture6;
};

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

먼저 정육면체의 점 위치를 저장할 VBO와 VAO를 선언하고 각 면에 붙일 텍스쳐를 6개 선언한다

startup에서 vertices[]배열 안에 삼각형 꼭지점의 좌표,색,가져올 텍스쳐의 좌표를 지정한다

한줄 앞의 3 값은 x,y,z값

4~6의 값은 r,g,b 값

7~8의 값은 가져올 텍스쳐의 좌표이다.

0번째부터 3칸까지 location = 0으로 보냄

4번째부터 6칸까지 location = 1로 보냄

7~8칸은 location =2로 보냄

startup의 텍스처 처리 부분이다

png 이미지 파일을 불러와서 data1에 저장하고 GL_TEXTURE_2D에 텍스처를 생성한다.

보낸 값은 쉐이더에서 in 으로 불러온다.

render함수에서 텍스처연결은 다음과 같다

uniform을 통해 쉐이더에서 선언한 texture1로 텍스처를 보내서 bind하고

glDrawArrays를 사용해 한쪽 면(0~6)은 같은 텍스처,

두번째 면(7~12)

세번째 면(13~18)... 이런식으로 다른 텍스처를 보내고 그려주는 것을 반복한다.