[OpenGL]VAO 와 VBO응용

후이재·2020년 9월 9일
2
post-thumbnail

VAO(Vertex Array Object)란

  • VAO란 연결한 Attribute의 링크정보를 담는 Array
  • Gen -> Bind 의 순서로 사용 가능함
  • 링크정보를 넣어줄 VAO를 bind한 후에 Attribute를 링크해주면 저장 가능
glGenVertexArrays(1, VertexArrayID);
glBindVertexArray(VertexArrayID[0]); 

VBO(Vertex Buffer Object)란

  • VBO는 그리고싶은 데이터를 넣어두는 버퍼
  • Gen -> Bind -> Data 의순서로 사용 가능함
  • 버퍼안의 데이터를 사용하고 싶다면, Attribute를 연결해줘야 함
glGenBuffers(2, Buffers);
glBindBuffer(GL_ARRAY_BUFFER, Buffers[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), 

어떻게 활용할 수 있는가

  • Gen으로 여러개의 VAO를 만들고, Bind를 통해 VAO에 넣어줄 링크를 분리하면 renderScene에서 VAO Bind를 바꿔주는 것 만으로도 따로 점을 분리할 필요 없이 다른 객체를 그릴 수 있다.
  • 아래의 코드는 2개의 VAO, VBO를 만든 후에 VAO[0]에는 삼각형 정보를, VAO[1]에는 점의 정보를 넣어주는것으로 분리를 했다. 따라서, 마우스 클릭으로 점을 추가할 때 VAO[1]로 Bind한 후 새로운 정보를 넣어주면 된다.
  • 그 후에, 그려줄 때는 0과 연결하고 그려주고, 1과 연결하고 그려주면 된다.

VertexShader.txt

#version 400 core

in vec3 pos;
void main()
{	
	gl_Position = vec4 (pos, 1);
	gl_PointSize = 10.0f;
}

FragmentShader.txt

#version 400 core

out vec3 color;

void main()
{
	color = vec3(1, 0, 0);
}

main.cpp

#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>

#include <GL/glew.h>
#include <GL/glut.h>
#include <algorithm>


using namespace std;
GLuint VertexArrayID[2]; // VAO
GLuint Buffers[2]; // VBO

vector<float> vertices = {
	0.01f, 0.01f, 0.0f,
	0.5f, 0.01f, 0.0f,
	0.01f, 0.5f, 0.0f,

	-0.01f, 0.01f, 0.0f,
	-0.5f, 0.01f, 0.0f,
	-0.01f, 0.5f, 0.0f,

	-0.01f, -0.01f, 0.0f,
	-0.5f, -0.01f, 0.0f,
	-0.01f, -0.5f, 0.0f,

	0.01f, -0.01f, 0.0f,
	0.5f, -0.01f, 0.0f,
	0.01f, -0.5f, 0.0f
};

vector<float> vertices_point = {};


GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path)
{
	//create the shaders
	GLuint VertexShaderID = glCreateShader(GL_VERTEX_SHADER);
	GLuint FragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);

	GLint Result = GL_FALSE;
	int InfoLogLength;

	//Read the vertex shader code from the file
	string VertexShaderCode;
	ifstream VertexShaderStream(vertex_file_path, ios::in);
	if (VertexShaderStream.is_open())
	{
		string Line = "";
		while (getline(VertexShaderStream, Line))
			VertexShaderCode += "\n" + Line;
		VertexShaderStream.close();
	}

	//Compile Vertex Shader
	printf("Compiling shader : %s\n", vertex_file_path);
	char const* VertexSourcePointer = VertexShaderCode.c_str();
	glShaderSource(VertexShaderID, 1, &VertexSourcePointer, NULL);
	glCompileShader(VertexShaderID);

	//Check Vertex Shader
	glGetShaderiv(VertexShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(VertexShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	vector<char> VertexShaderErrorMessage(InfoLogLength);
	if (InfoLogLength != 0) {
		glGetShaderInfoLog(VertexShaderID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
		fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);
	}

	//Read the fragment shader code from the file
	string FragmentShaderCode;
	ifstream FragmentShaderStream(fragment_file_path, ios::in);
	if (FragmentShaderStream.is_open())
	{
		string Line = "";
		while (getline(FragmentShaderStream, Line))
			FragmentShaderCode += "\n" + Line;
		FragmentShaderStream.close();
	}

	//Compile Fragment Shader
	printf("Compiling shader : %s\n", fragment_file_path);
	char const* FragmentSourcePointer = FragmentShaderCode.c_str();
	glShaderSource(FragmentShaderID, 1, &FragmentSourcePointer, NULL);
	glCompileShader(FragmentShaderID);

	//Check Fragment Shader
	glGetShaderiv(FragmentShaderID, GL_COMPILE_STATUS, &Result);
	glGetShaderiv(FragmentShaderID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	vector<char> FragmentShaderErrorMessage(InfoLogLength);
	if (InfoLogLength != 0) {
		glGetShaderInfoLog(FragmentShaderID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
		fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);
	}

	//Link the program
	fprintf(stdout, "Linking program\n");
	GLuint ProgramID = glCreateProgram();
	glAttachShader(ProgramID, VertexShaderID);
	glAttachShader(ProgramID, FragmentShaderID);
	glLinkProgram(ProgramID);

	// Check the program
	glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
	glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
	vector<char> ProgramErrorMessage(max(InfoLogLength, int(1)));
	if (InfoLogLength != 0) {
		glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
		fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);
	}

	glDeleteShader(VertexShaderID);
	glDeleteShader(FragmentShaderID);

	return ProgramID;
}


void renderScene(void)
{
	//Clear all pixels
	glClear(GL_COLOR_BUFFER_BIT);
	//Let's draw something here
	glBindVertexArray(VertexArrayID[0]);
	glDrawArrays(GL_TRIANGLES, 0, vertices.size()/3);

	glBindVertexArray(VertexArrayID[1]);
	glDrawArrays(GL_POINTS, 0, vertices_point.size()/3);

	//Double buffer
	glutSwapBuffers();
}


void init()
{
	//initilize the glew and check the errors.
	GLenum res = glewInit();
	if (res != GLEW_OK)
	{
		fprintf(stderr, "Error: '%s' \n", glewGetErrorString(res));
	}

	//select the background color
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
}

void myMouseFunc(int btn, int state, int x, int y) {
	if (state == GLUT_DOWN && btn == GLUT_LEFT_BUTTON) {
		float nx = 2.0f * (float)x / (float)479 - 1.0f; //mapping to world coordinate
		float ny = -2.0f * (float)y / (float)479 + 1.0f;

		vertices_point.push_back(nx);//vertices
		vertices_point.push_back(ny);
		vertices_point.push_back(0.0f);

		glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices_point.size(), vertices_point.data(), GL_STATIC_DRAW); // data update
		glutPostRedisplay();//re-draw
	}
}

int main(int argc, char **argv)
{
	//init GLUT and create Window
	//initialize the GLUT
	glutInit(&argc, argv);
	//GLUT_DOUBLE enables double buffering (drawing to a background buffer while the other buffer is displayed)
	glutInitDisplayMode(/* GLUT_3_2_CORE_PROFILE | */ GLUT_DOUBLE | GLUT_RGBA);
	//These two functions are used to define the position and size of the window. 
	glutInitWindowPosition(200, 200);
	glutInitWindowSize(480, 480);
	//This is used to define the name of the window.
	glutCreateWindow("Simple OpenGL Window");

	//call initization function
	init();

	//0. 
	//Generate ID
	GLuint programID = LoadShaders("VertexShader.txt", "FragmentShader.txt");
	glUseProgram(programID);

	//1.
	//Generate VAO
	glGenVertexArrays(1, VertexArrayID);

	//2.
	//Generate VBO
	glGenBuffers(2, Buffers);

	// VAO1
	glBindVertexArray(VertexArrayID[0]); 
	glBindBuffer(GL_ARRAY_BUFFER, Buffers[0]); // for triangles
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW);

	//link Attribute
	GLint posAttrib = glGetAttribLocation(programID, "pos");
	glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(posAttrib);

	// VAO2
	glBindVertexArray(VertexArrayID[1]); 
	glBindBuffer(GL_ARRAY_BUFFER, Buffers[1]); // for points
	glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices_point.size(), vertices_point.data(), GL_STATIC_DRAW);

	//link Attribute
	posAttrib = glGetAttribLocation(programID, "pos");
	glVertexAttribPointer(posAttrib, 3, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(posAttrib);

	glutDisplayFunc(renderScene);

	//Set Function
	glutMouseFunc(myMouseFunc);

	//enter GLUT event processing cycle
	glutMainLoop();

	glDeleteVertexArrays(1, VertexArrayID);

	return 1;
}
profile
공부를 위한 벨로그

0개의 댓글