opengl

opengl 바람개비 회전 - 유니폼 VBO 사용

현구구 2022. 9. 6. 14:29

 


//배경색 칠하기//////////////////////////////////////////
// sb6.h 헤더 파일을 포함시킨다.
#include <sb7.h>
#include <vmath.h> //수학 함수 해더파일 sin,cos
// sb6::application을 상속받는다.
class my_application : public sb7::application
{
public: //쉐이더 컴파일 과정
	// 렌더링 virtual 함수를 작성해서 오버라이딩한다.

	GLuint compile_shaders(void)
	{
		GLuint vertex_shader;
		GLuint fragment_shader;
		GLuint program;
		program = glCreateProgram();

		const GLchar* vertex_shader_source[] =
		{
			"#version 430 core\n"
			"layout (location = 0) in vec3 pos;\n"
			"layout (location = 1) in vec3 color;\n"
			"layout (location = 2) in vec3 colormove;\n"
			"uniform mat4 rotMat;\n" //선언을 여기서함
			"out vec3 vsColor;\n"
			"void main(void)\n"
			"{\n"
			"gl_Position = rotMat*vec4(pos.x,pos.y,pos.z,1.0);\n"
			"vsColor= color+colormove;\n"
			"}\n"
		};
		const GLchar* fragment_shader_source[] =
		{
			"#version 430 core                          \n"
			"in vec3 vsColor;\n"
			"                                           \n"
			"out vec4 fragColor;                            \n"
			"                                           \n"
			"void main(void)                            \n"
			"{                                          \n"
			"   fragColor = vec4(vsColor, 1.0);   \n"
			"}                                          \n"
		};

		vertex_shader = glCreateShader(GL_VERTEX_SHADER); //버텍스 쉐이더 생성
		fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);

		glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
		glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);

		glCompileShader(vertex_shader);
		glCompileShader(fragment_shader);

		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);
		//삼각형 세 점의 위치와 색 정의
		GLfloat vertices[] = {
			0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
			0.0f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
			-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
			0.5f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f,
			0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
			-0.5f, 0.0f, 0.5f, 0.0f, 1.0f, 0.0f,
			-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
			0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f,
			0.0f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
			0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f

		};
		//VBO를 생성하여 vertices 값들을 복사
		GLuint VBO;
		glGenBuffers(1, &VBO);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * 4, (void*)0);
		glEnableVertexAttribArray(0);

		glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * 4, (void*)(12));
		glEnableVertexAttribArray(1);

		glBindBuffer(GL_ARRAY_BUFFER, 0);
		glBindVertexArray(0);
	}
	virtual void shutdown()
	{
		glDeleteVertexArrays(1, &VAO);
		glDeleteProgram(rendering_program);
	}
	virtual void render(double currentTime) // = tick함수 무한반복 currentTime -> 1초 / render virtual 로 재정의(override)
	{
		//===============================배경=========================
		const GLfloat red[] = { (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);
		//=============================================================
		GLfloat colormove[] = { (float)sin(currentTime) * 0.5f, (float)cos(currentTime) * 0.5f, 0.0f, 0.0f };
		glVertexAttrib4fv(2, colormove);
		//================================================
		glUseProgram(rendering_program);

		float angle = currentTime * 50;
		vmath::mat4 rm = vmath::rotate(angle, 0.0f, 0.0f, 1.0f);
		GLint rotMatLocation = glGetUniformLocation(rendering_program, "rotMat");//rendering_program에 있는 rotMat 위치 받아옴

		glUniformMatrix4fv(rotMatLocation, 1, GL_FALSE, rm);//받아왓으면 그 rotMatLocation에 rm 넣어줌

		glBindVertexArray(VAO);//미리 설정한 vao를 그리기 위해 바인드한다

		glDrawArrays(GL_TRIANGLES, 0, 12);

	} //모든 OpenGL 함수는 gl 로 시작 
private:
	GLuint rendering_program;
	GLuint VAO;
};

// DECLARE_MAIN의 하나뿐인 인스턴스
DECLARE_MAIN(my_application) // int main() 대체, class명 삽입

먼저 startup 함수에서 점의 위치와 점의 색을 정해준다

첫 줄 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f 의 경우 앞의 3개의 float 0.0, 0.0, 0.5는 점의 위치를,

뒤의 3개 1.0, 0.0, 0.0은 점의 색을 나타낸다.

저장한 vertices는 버텍스 쉐이더로 보내준다.

첫 줄 0.0f, 0.0f, 0.5f, 1.0f, 0.0f, 0.0f 의 경우 인덱스는 앞에서부터 0 - 1 - 2 - 3 - 4 - 5이다.

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * 4, (void*)0); 에서 

0은 버텍스쉐이더로 보낼 layout인덱스를 나타낸다

3은 원소의 개수

6 * 4 에서 6은 한 줄의 원소개수(x,y,z,r,g,b) 4는 한 원소의 size (float의 size는 4)

(void*)0은 한 줄에서 시작할 인덱스이다 점 위치의 경우 0번인덱스에서 시작한다

(void*)12는 4(float size) * 3(한 줄에서 시작할 인덱스)를 나타낸다 즉 3번 인덱스부터 점의 색을 나타낸다

스타트업에서 지정해준 점의 위치와 점의 색은 버텍스 쉐이더로 보내준다

 

마지막으로

프래그먼트 쉐이더에서 uniform을 하나 생성한다 변수 이름은 rotMat

선언한 변수 rotMat는 render함수에서 설정해준다

위 코드는

1. x축 방향으로 돌도록 변수 rm 을 선언하고

2. 버텍스 쉐이더에 있는 rotMat uniform을 받아오는 rotMatLocation 변수를 하나 선언한다

3. 그 다음  rotMatLocation에 rm을 넣어주면 버텍스쉐이더로 변수가 넘어간다


//배경색 칠하기//////////////////////////////////////////
// sb6.h 헤더 파일을 포함시킨다.
#include <sb7.h>
#include <vmath.h> //수학 함수 해더파일 sin,cos
// sb6::application을 상속받는다.
class my_application : public sb7::application
{
public: //쉐이더 컴파일 과정
	GLuint compile_shaders(void)
	{
		//쉐이더 객체 생성
		GLuint vertex_shader_pung;
		vertex_shader_pung = glCreateShader(GL_VERTEX_SHADER);
		GLuint fragment_shader_pung;
		fragment_shader_pung = glCreateShader(GL_FRAGMENT_SHADER);

		//쉐이더 소스 코드
		const GLchar* vertex_shader_source_pung[] =
		{
			//"#version 430 core\n"
			//"\n"
			//"void main(void)\n"
			//"{\n"
			//"	gl_Position = vec4(0.0, 0.0, 0.5, 1.0);\n" //이게 중앙이래
			//"}\n" //얘는 점 위치

			"#version 430 core\n"
			"\n"

			"layout(location = 0) in vec4 offset;\n"
			"layout(location = 5) in float angle_vs;\n"
			"out vec4 vs_color;\n"
			"void main(void)\n"
			"{\n"
			//점위치
			"	const vec4 vertices[12] = vec4[12](vec4(0.0, 0.0, 0.5, 1.0),\n"
			"		vec4(0.0, 0.5, 0.5, 1.0),\n"
			"		vec4(-0.5, 0.5, 0.5, 1.0),\n"
			"vec4(0.0, 0.0, 0.5, 1.0),\n"
			"vec4(0.5, 0.0, 0.5, 1.0),\n"
			"vec4(0.5, 0.5, 0.5, 1.0),\n"
			"vec4(0.0, 0.0, 0.5, 1.0),\n"
			"vec4(-0.5, 0.0, 0.5, 1.0),\n"
			"vec4(-0.5, -0.5, 0.5, 1.0),\n"
			"vec4(0.0, 0.0, 0.5, 1.0),\n"
			"vec4(0.0, -0.5, 0.5, 1.0),\n"
			"vec4(0.5, -0.5, 0.5, 1.0));\n"
			//회전행렬
			"mat4 m1;\n"
			"m1[0] = vec4(cos(angle_vs),sin(angle_vs),0.0,0.0);\n"
			"m1[1] = vec4(-sin(angle_vs),cos(angle_vs),0.0,0.0);\n"
			"m1[2] = vec4(0.0,0.0,1.0,0.0);\n"
			"m1[3] = vec4(0.0,0.0,0.0,1.0);\n"
			//위치에 회전행렬 곱해줌
			"	gl_Position = m1*vertices[gl_VertexID];\n"
			//컬러부분
			"	const vec4 colors[12] = vec4[12](vec4(1.0, 0.0, 0.0, 1.0),\n"
			"		vec4(0.0, 1.0, 0.0, 1.0),\n"
			"		vec4(0.0, 0.0, 1.0, 1.0),\n"
			"		vec4(1.0, 0.0, 0.0, 1.0),\n"
			"		vec4(0.0, 1.0, 0.0, 1.0),\n"
			"		vec4(0.0, 0.0, 1.0, 1.0),\n"
			"		vec4(1.0, 0.0, 0.0, 1.0),\n"
			"		vec4(0.0, 1.0, 0.0, 1.0),\n"
			"		vec4(0.0, 0.0, 1.0, 1.0),\n"
			"		vec4(1.0, 0.0, 0.0, 1.0),\n"
			"		vec4(0.0, 1.0, 0.0, 1.0),\n"
			"		vec4(0.0, 0.0, 1.0, 1.0));\n"
			"	vs_color = colors[gl_VertexID]+offset;\n"
			"}\n"
		};

		//프래그먼트 소스코드
		const GLchar* fragment_shdaer_source_pung[] =
		{
			"#version 430 core\n"
			"in vec4 vs_color;\n"
			"out vec4 color;\n"
			"void main(void)\n"
			"{\n"
			"	color = vs_color;\n"
			"}\n"
		};
		//쉐이더 소스코드 쉐이더 객체로 전달
		glShaderSource(vertex_shader_pung, 1, vertex_shader_source_pung, NULL);
		glShaderSource(fragment_shader_pung, 1, fragment_shdaer_source_pung, NULL);
		//쉐이더 객체의 소스 코드 컴파일 mack
		glCompileShader(vertex_shader_pung);
		glCompileShader(fragment_shader_pung);
		//프로그램 객체 생성
		GLuint program_pung;
		program_pung = glCreateProgram();




		//쉐이더 객체를 프로그램에 어태치 시킴
		glAttachShader(program_pung, vertex_shader_pung);
		glAttachShader(program_pung, fragment_shader_pung);

		//프로그램 객체에 어태치 시킨 쉐이더 객채들을 링크함
		glLinkProgram(program_pung);

		//쉐이더 객체들을 삭제한다
		glDeleteShader(vertex_shader_pung);
		glDeleteShader(fragment_shader_pung);

		return program_pung; //program 을 리턴해줌

	}
	GLuint compile_shaders_mack(void)
	{
		//쉐이더 객체 생성
		GLuint vertex_shader_mack;
		vertex_shader_mack = glCreateShader(GL_VERTEX_SHADER);
		GLuint fragment_shader_mack;
		fragment_shader_mack = glCreateShader(GL_FRAGMENT_SHADER);

		//쉐이더 소스 코드
		const GLchar* vertex_shader_source_mack[] =
		{

			"#version 430 core\n"
			"\n"

			"void main(void)\n"
			"{\n"
			"	const vec4 vertices[6] = vec4[6](vec4(-0.01, 0.0, 0.5, 1.0),\n"
			"		vec4(-0.01, -1, 0.5, 1.0),\n"
			"		vec4(0.01, -1.0, 0.5, 1.0),\n"
			"vec4(-0.01, 0.0, 0.5, 1.0),\n"
			"vec4(0.01, 0, 0.5, 1.0),\n"
			"vec4(0.01, -1.0, 0.5, 1.0));\n"
			"	gl_Position = vertices[gl_VertexID];\n"
			"}\n"
		};

		//프래그먼트 소스코드
		const GLchar* fragment_shdaer_source_mack[] =
		{
			"#version 430 core\n"
			"out vec4 color;\n"
			"void main(void)\n"
			"{\n"
			"	color = vec4(0,1,0.8,1);\n"
			"}\n"
		};
		//쉐이더 소스코드 쉐이더 객체로 전달
		glShaderSource(vertex_shader_mack, 1, vertex_shader_source_mack, NULL);
		glShaderSource(fragment_shader_mack, 1, fragment_shdaer_source_mack, NULL);
		//쉐이더 객체의 소스 코드 컴파일 mack
		glCompileShader(vertex_shader_mack);
		glCompileShader(fragment_shader_mack);
		//프로그램 객체 생성
		GLuint program_mack;
		program_mack = glCreateProgram();




		//쉐이더 객체를 프로그램에 어태치 시킴
		glAttachShader(program_mack, vertex_shader_mack);
		glAttachShader(program_mack, fragment_shader_mack);

		//프로그램 객체에 어태치 시킨 쉐이더 객채들을 링크함
		glLinkProgram(program_mack);

		//쉐이더 객체들을 삭제한다
		glDeleteShader(vertex_shader_mack);
		glDeleteShader(fragment_shader_mack);

		return program_mack; //program 을 리턴해줌

	}

	virtual void startup() //애플리케이션 초기화 가상함수
	{
		rendering_program = compile_shaders();//쉐이더 및 프로그램 재 컴파일 안하도록 일련의 과정 startup에 저장//리턴값인 program 이 들어옴
		glGenVertexArrays(1, &vertex_array_object);
		glBindVertexArray(vertex_array_object);
		//===================================================================
		rendering_program_mack = compile_shaders_mack();
		glGenVertexArrays(1, &vertex_array_object_mack);
		glBindVertexArray(vertex_array_object_mack);
	}

	virtual void shutdown()//애플리케이션 종료시 호출되는 함수
	{
		glDeleteVertexArrays(1, &vertex_array_object);
		glDeleteProgram(rendering_program);
		//====================================================================
		glDeleteVertexArrays(1, &vertex_array_object_mack);
		glDeleteProgram(rendering_program_mack);
	}

	// 렌더링 virtual 함수를 작성해서 오버라이딩한다.
	virtual void render(double currentTime) // = tick함수 무한반복 currentTime -> 1초 / render virtual 로 재정의(override)
	{
		//====================배경===========================
		const GLfloat black[] = { 0.0f, 0.0f, 0.0f, 1.0f };

		const GLfloat red[] =
		{
			(float)sin(currentTime) * 0.5f + 0.5f, 1.0f, 0.5f, 1.0f
		};
		//배경 색깔
		glClearBufferfv(GL_COLOR, 0, black);
		//============================================================
		GLfloat attrib[] = { (float)sin(currentTime) * 0.5f, (float)cos(currentTime) * 0.5f, 0.0f, 0.0f };
		glVertexAttrib4fv(0, attrib);//vertax shader 로 넘길 값 index 는 0 
		GLfloat color[] = { 0.0f, 1.0f, 1.0f, 0.0f };
		glVertexAttrib4fv(1, color);

		//프로그램 실행 막대=================================

		glUseProgram(rendering_program_mack);
		glDrawArrays(GL_TRIANGLES, 0, 6);
		//프로그램 실행 바람개비============================================
		glUseProgram(rendering_program);

		float angle = currentTime;
		glVertexAttrib1f(5, angle);

		glDrawArrays(GL_TRIANGLES, 0, 12); //삼각형 점이 3개 필요 

	} //모든 OpenGL 함수는 gl 로 시작 

private:
	GLuint rendering_program;
	GLuint vertex_array_object;

	GLuint rendering_program_mack;
	GLuint vertex_array_object_mack;
};


// DECLARE_MAIN의 하나뿐인 인스턴스
DECLARE_MAIN(my_application) // int main() 대체, class명 삽입

VBO 와 uniform을 사용 안하고 버텍스쉐이더에서 하드코딩하여 바람개비를 만드는 코드는 다음과 같다.