opengl

opengl 삼각형 폴리곤 모드 - 테셀레이션, 지오메트리 쉐이더

현구구 2022. 8. 24. 17:00

#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;
		vertex_shader = glCreateShader(GL_VERTEX_SHADER); //버텍스 쉐이더 생성
		GLuint fragment_shader;
		fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
		GLuint TCS;
		TCS = glCreateShader(GL_TESS_CONTROL_SHADER);
		GLuint TES;
		TES = glCreateShader(GL_TESS_EVALUATION_SHADER);

		GLuint program;
		program = glCreateProgram();

		const GLchar* vertex_shader_source[] =
		{
			"#version 430 core\n"
			"layout (location = 0) in vec4 move;\n"
			"layout (location = 1) in vec4 color;\n"
			"out vec4 color_vertex;\n"
			"void main(void)\n"
			"{\n"
			"const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),\n"
			"vec4(-0.25, 0.25, 0.5, 1.0),\n"
			"vec4(0.25, 0.25, 0.5,1.0));\n"
			"gl_Position = vertices[gl_VertexID]+move;\n"
			"color_vertex= color;\n"
			"}\n"
		};
		const GLchar* fragment_shader_source[] =
		{
			"#version 430 core                          \n"
			"in vec4 color_vertex;\n"
			"                                           \n"
			"out vec4 color;                            \n"
			"                                           \n"
			"void main(void)                            \n"
			"{                                          \n"
			"   color = vec4(0.0,0.8,1.0,1.0);   \n"
			"}                                          \n"
		};
		static const GLchar* TCS_source[] = //tcs 
		{
			"#version 430 core\n"
			"layout (vertices = 3) out;\n"
			"void main(void)\n"
			"{\n"
			"if(gl_InvocationID==0){\n" //glvertexid 와 똑같다 반복적인 작업을 하지 않기 위해서 점이 0일때만 실행
			"gl_TessLevelInner[0] = 5.0;\n"
			"gl_TessLevelOuter[0] = 5.0;\n"
			"gl_TessLevelOuter[1] = 5.0;\n"
			"gl_TessLevelOuter[2] = 5.0;\n"
			"}\n"
			"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n" //분할한 점들을 출력
			"}\n"
		};
		static const GLchar* TES_source[] =
		{
			"#version 430 core\n"
			"layout (triangles, equal_spacing, cw) in;\n"
			"void main(void)\n"
			"{\n"
			"gl_Position = (gl_TessCoord.x*gl_in[0].gl_Position +\n"//gl_TessCoord.x는 무게중심 좌표 여기서는 1/3
			"gl_TessCoord.y*gl_in[1].gl_Position +\n"
			"gl_TessCoord.z*gl_in[2].gl_Position);\n" //제어점의 개수 3개 위에서 out 한거
			"}\n"
		};
		glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
		glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
		glShaderSource(TCS, 1, TCS_source, NULL);
		glShaderSource(TES, 1, TES_source, NULL);

		glCompileShader(vertex_shader);
		glCompileShader(fragment_shader);
		glCompileShader(TCS);
		glCompileShader(TES);

		glAttachShader(program, vertex_shader);
		glAttachShader(program, fragment_shader);
		glAttachShader(program, TCS);
		glAttachShader(program, TES);

		glLinkProgram(program);

		glDeleteShader(vertex_shader);
		glDeleteShader(fragment_shader);
		glDeleteShader(TCS);
		glDeleteShader(TES);

		return program;
	}
	virtual void startup()
	{
		rendering_program = compile_shaders();
		glGenVertexArrays(1, &vertex_array_object);
		glBindVertexArray(vertex_array_object);
	}
	virtual void shutdown()
	{
		glDeleteVertexArrays(1, &vertex_array_object);
		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 };
		//static 이면 안됨 색 안바뀜
		glClearBufferfv(GL_COLOR, 0, red);
		//==========================================
		GLfloat move[] = { (float)sin(currentTime) * 0.5f, (float)cos(currentTime) * 0.5f, 0.0f, 0.0f };
		glVertexAttrib4fv(0, move);

		GLfloat color[] = { 0.0f, 0.8f, 1.0f, 1.0f };
		glVertexAttrib4fv(1, color);
		//========================================================
		glUseProgram(rendering_program);
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glDrawArrays(GL_PATCHES, 0, 3); //tes쓸거면 glpatches 사용
	} //모든 OpenGL 함수는 gl 로 시작 
private:
	GLuint rendering_program;
	GLuint vertex_array_object;
};


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

폴리곤 모드로 나타내기 위해서는 테셀레이션 쉐이더를 사용해야한다

TCS쉐이더에서는 분할을 한 점의 개수를 정한다 

gl_TessLevelInner[0]은 삼각형 중앙으로부터 분할할 개수

gl_TessLevelOuter은 삼각형의 각 변을 분할할 개수이다.

분할할 개수를 정해주면 이를 저장하고

TES 쉐이더에서는 TCS쉐이더에서 지정한 점 대로 폴리곤모드를 수행하도록 처리한다.

render 함수에서는 glPolygonMode를 삼각형을 그리기전에 작성해주고

glDrawArrays에서는 GL_TRIANGLES가 아닌 GL_PATCHES 를 사용하여 삼각형을 그려준다.

 


#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;
		vertex_shader = glCreateShader(GL_VERTEX_SHADER); //버텍스 쉐이더 생성
		GLuint fragment_shader;
		fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
		GLuint TCS;
		TCS = glCreateShader(GL_TESS_CONTROL_SHADER);
		GLuint TES;
		TES = glCreateShader(GL_TESS_EVALUATION_SHADER);
		GLuint gs;
		gs = glCreateShader(GL_GEOMETRY_SHADER);

		GLuint program;
		program = glCreateProgram();

		const GLchar* vertex_shader_source[] =
		{
			"#version 430 core\n"
			"layout (location = 0) in vec4 move;\n"
			"layout (location = 1) in vec4 color;\n"
			"out vec4 color_vertex;\n"
			"void main(void)\n"
			"{\n"
			"const vec4 vertices[3] = vec4[3](vec4(0.25, -0.25, 0.5, 1.0),\n"
			"vec4(-0.25, 0.25, 0.5, 1.0),\n"
			"vec4(0.25, 0.25, 0.5,1.0));\n"
			"gl_Position = vertices[gl_VertexID]+move;\n"
			"color_vertex= color;\n"
			"}\n"
		};
		const GLchar* fragment_shader_source[] =
		{
			"#version 430 core                          \n"
			"in vec4 color_vertex;\n"
			"                                           \n"
			"out vec4 color;                            \n"
			"                                           \n"
			"void main(void)                            \n"
			"{                                          \n"
			"   color = vec4(0.0,0.8,1.0,1.0);   \n"
			"}                                          \n"
		};
		static const GLchar* TCS_source[] =
		{
			"#version 430 core\n"
			"layout (vertices = 3) out;\n"
			"void main(void)\n"
			"{\n"
			"if(gl_InvocationID==0){\n"
			"gl_TessLevelInner[0] = 5.0;\n"
			"gl_TessLevelOuter[0] = 5.0;\n"
			"gl_TessLevelOuter[1] = 5.0;\n"
			"gl_TessLevelOuter[2] = 5.0;\n"
			"}\n"
			"gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;\n"
			"}\n"
		};
		static const GLchar* TES_source[] =
		{
			"#version 430 core\n"
			"layout (triangles, equal_spacing, cw) in;\n"
			"void main(void)\n"
			"{\n"
			"gl_Position = (gl_TessCoord.x*gl_in[0].gl_Position +\n"
			"gl_TessCoord.y*gl_in[1].gl_Position +\n"
			"gl_TessCoord.z*gl_in[2].gl_Position);\n"
			"}\n"
		};
		static const GLchar* gs_source[] =
		{
			"#version 430 core\n"
			"layout (triangles) in;\n"
			"layout (points, max_vertices = 3) out;\n" //점으로 출력되게끔 points 
			"void main(void)\n"
			"{\n"
			"for(int i = 0; i < gl_in.length();i++){\n"
			"gl_Position = gl_in[i].gl_Position;\n" //점 개수만큼 출력
			"EmitVertex();\n"
			"}\n"
			"}\n"
		};
		glShaderSource(vertex_shader, 1, vertex_shader_source, NULL);
		glShaderSource(fragment_shader, 1, fragment_shader_source, NULL);
		glShaderSource(TCS, 1, TCS_source, NULL);
		glShaderSource(TES, 1, TES_source, NULL);
		glShaderSource(gs, 1, gs_source, NULL);

		glCompileShader(vertex_shader);
		glCompileShader(fragment_shader);
		glCompileShader(TCS);
		glCompileShader(TES);
		glCompileShader(gs);

		glAttachShader(program, vertex_shader);
		glAttachShader(program, fragment_shader);
		glAttachShader(program, TCS);
		glAttachShader(program, TES);
		glAttachShader(program, gs);

		glLinkProgram(program);

		glDeleteShader(vertex_shader);
		glDeleteShader(fragment_shader);
		glDeleteShader(TCS);
		glDeleteShader(TES);
		glDeleteShader(gs);

		return program;
	}
	virtual void startup()
	{
		rendering_program = compile_shaders();
		glGenVertexArrays(1, &vertex_array_object);
		glBindVertexArray(vertex_array_object);
	}
	virtual void shutdown()
	{
		glDeleteVertexArrays(1, &vertex_array_object);
		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 };
		//static 이면 안됨 색 안바뀜
		glClearBufferfv(GL_COLOR, 0, red);
		//====================================================================================
		GLfloat move[] = { (float)sin(currentTime) * 0.5f, (float)cos(currentTime) * 0.5f, 0.0f, 0.0f };
		glVertexAttrib4fv(0, move);

		GLfloat color[] = { 0.0f, 0.0f, 1.0f, 0.0f };
		glVertexAttrib4fv(1, color);
		//===============================================
		glUseProgram(rendering_program);
		glPointSize(5.0f);
		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
		glDrawArrays(GL_PATCHES, 0, 3);
	} //모든 OpenGL 함수는 gl 로 시작 
private:
	GLuint rendering_program;
	GLuint vertex_array_object;
};


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

지오메트리 쉐이더에서는 테셀레이션에서 다루었던 모든 점에 대해 접근 할 수 있다.

받는건 삼각형이었지만 출력은 점으로 출력되게끔 points로 출력하도록 한다.

for문을 돌려 모든 점에 대해서 gl_Position을 지정하고 EmitVertex를 통해 출력하도록 한다.

render 함수에서는 다음과 같이 설정하여 점의 크기를 정해주고 화면에 그리도록 한다.


 

gs쉐이더에서 코드를 다음과 같이 바꾸면 점의 개수가 2배가 된다.

max_vertices를 3에서 6으로 늘리고 각 점의 위치에 -1를 곱해주어 위치를 반전시킨다음 한번더 EmitVertex를 하여 출력하면 점의 개수가 2배가 된다.

'opengl' 카테고리의 다른 글

opengl 바람개비 보간  (0) 2022.09.06
opengl 삼각형 보간  (0) 2022.08.25
opengl 움직이는 삼각형  (0) 2022.08.23
opengl 삼각형 그리기  (0) 2022.08.22
opengl 점찍기 - 배경색상 변경  (0) 2022.08.22