실행 화면

 

소스코드

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <string>

GLuint VBO, VAO, shader;

std::string ReadFile(const char* filePath)
{
	std::string content;
	std::ifstream fileStream(filePath, std::ios::in);

	while (!fileStream.is_open())
	{
		printf("Failed to read %s file! The file doesn't exist.\n", filePath);
		return "";
	}

	std::string line = "";
	while (!fileStream.eof())
	{
		std::getline(fileStream, line);
		content.append(line + "\n");
	}

	fileStream.close();
	return content;
}

GLuint AddShader(const char* shaderCode, GLenum shaderType)
{
	GLuint new_shader = glCreateShader(shaderType);

	const GLchar* code[1];
	code[0] = shaderCode;

	glShaderSource(new_shader, 1, code, NULL);

	GLint result = 0;
	GLchar err_log[1024] = { 0 };

	glCompileShader(new_shader);
	glGetShaderiv(new_shader, GL_COMPILE_STATUS, &result);
	if (!result)
	{
		glGetShaderInfoLog(new_shader, sizeof(err_log), NULL, err_log);
		printf("Error compiling the %d shader: '%s'\n", shaderType, err_log);
		return 0;
	}
	return new_shader;
}

void CompileShader(const char* vsCode, const char* fsCode)
{
	GLuint vs, fs;

	shader = glCreateProgram();

	if (!shader)
	{
		printf("Error: Cannot create shader program.");
		return;
	}

	vs = AddShader(vsCode, GL_VERTEX_SHADER);
	fs = AddShader(fsCode, GL_FRAGMENT_SHADER);
	glAttachShader(shader, vs);  // Attach shaders to the program for linking process.
	glAttachShader(shader, fs);

	GLint result = 0;
	GLchar err_log[1024] = { 0 };

	glLinkProgram(shader);  // Create executables from shader codes to run on corresponding processors.
	glGetProgramiv(shader, GL_LINK_STATUS, &result);
	if (!result)
	{
		glGetProgramInfoLog(shader, sizeof(err_log), NULL, err_log);
		printf("Error linking program: '%s'\n", err_log);
		return;
	}
}

void CreateShaderProgramFromFiles(const char* vsPath, const char* fsPath)
{
	std::string vsFile = ReadFile(vsPath);
	std::string fsFile = ReadFile(fsPath);
	const char* vsCode = vsFile.c_str();
	const char* fsCode = fsFile.c_str();

	CompileShader(vsCode, fsCode);
}

void CreateTriangle()
{
	GLfloat vertices[] = {
		-1.0f, -1.0f, 0.0f,
		1.0f, -1.0f, 0.0f,
		0.0f, 1.0f, 0.0f
	};

	glGenVertexArrays(1, &VAO);
	glBindVertexArray(VAO);

	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, 0, 0);
	glEnableVertexAttribArray(0);

	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glBindVertexArray(0);
}

int main(void)
{
	if (!glfwInit())
		exit(EXIT_FAILURE);

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

	GLFWwindow* window = glfwCreateWindow(1080, 720, "title", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	glfwMakeContextCurrent(window);

	int framebuf_width, framebuf_height;
	glfwGetFramebufferSize(window, &framebuf_width, &framebuf_height);
	glViewport(0, 0, framebuf_width, framebuf_height);

	if (glewInit() != GLEW_OK)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	CreateTriangle();
	CreateShaderProgramFromFiles("Shaders/shader.vert", "Shaders/shader.frag");

	while (!glfwWindowShouldClose(window))
	{
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);

		glUseProgram(shader);

		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);
		glBindVertexArray(0);

		glUseProgram(0);

		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwTerminate();

	return 0;
}

 

Vertex shader

#version 460

layout (location = 0) in vec3 pos;

void main()
{
	gl_Position = vec4(pos, 1.0);
}

#version GLSL버전

0번째 vetex attribute를 가져와 vec3 pos 변수에 넣음

gl_position은 미리 정의된 vertex shader의 출력값으로 clip-space에서의 vertex 좌표

 

Fragment shader

#version 460

out vec4 color;

void main()
{
    color = vec4(0.0, 1.0, 0.0, 1.0);
}

#version GLSL버전

출력 변수로 vec4 color 선언, 내장 변수가 아니므로 변수명은 마음대로

 

관습적으로 vetex shader의 파일명은 xxxx.vert로 fragment shader의 파일명은 xxxx.frag로 함

실행 화면

 

소스코드

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdlib.h>

int main(void)
{
	if (!glfwInit())
		exit(EXIT_FAILURE);

	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

	GLFWwindow* window = glfwCreateWindow(1080, 720, "title", NULL, NULL);
	if (!window)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	glfwMakeContextCurrent(window);

	int framebuf_width, framebuf_height;
	glfwGetFramebufferSize(window, &framebuf_width, &framebuf_height);
	glViewport(0, 0, framebuf_width, framebuf_height);

	if (glewInit() != GLEW_OK)
	{
		glfwTerminate();
		exit(EXIT_FAILURE);
	}

	// NDC space (-1.0 ~ 1.0)
	float vertices[] = {
	-0.5f, -0.5f, 0.0f,
	 0.5f, -0.5f, 0.0f,
	 0.0f,  0.5f, 0.0f
	};

	GLuint VAO;  // 아래 모든 작업을 하나의 state로 저장할 OpenGL Object ID (vertex array)
	GLuint VBO; // vertex buffer object ID (vertex buffer)

	glGenVertexArrays(1, &VAO); // VAO 생성
	glBindVertexArray(VAO); // VAO를 OpenGL context에 연결(bind)

	glGenBuffers(1, &VBO);  // pram:(만들고자 하는 버퍼의 갯수, 버퍼의 ID 포인터)
	glBindBuffer(GL_ARRAY_BUFFER, VBO);  // param:(target, 버퍼의 ID)
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // parm:(target, 복사할 데이터 크기, 복사할 데이터, 힌트)

	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GL_FLOAT), (void*)0); // location pointer parm:(0, 3차원, float, no normalize, stride, start offset)
	glEnableVertexAttribArray(0);

	//glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GL_FLOAT), (void*)(3 * sizeof(GL_FLOAT))); // uv pointer example
	//glEnableVertexAttribArray(1);

	glBindBuffer(GL_ARRAY_BUFFER, 0); // ID 대신 0을 넣으면 unbind
	glBindVertexArray(0);


	while (!glfwWindowShouldClose(window))
	{
		glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		glBindVertexArray(VAO);
		glDrawArrays(GL_TRIANGLES, 0, 3);
		glfwSwapBuffers(window);
		glfwPollEvents();
	}

	glfwTerminate();

	return 0;
}

 

함수 정리

glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4)

기계에서 호환하는 OpenGL major 버전 설정 

ex) Version 4.5 - Major 4

 

glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5)

기계에서 호환하는 OpenGL minor 버전 설정 

ex) Version 4.5 - Minor 5

 

glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE)

OpenGL Profile 설정

GLFW_OPENGL_CORE_PROFILE / GLFW_OPENGL_COMPAT_PROFILE / GLFW_OPENGL_ANY_PROFILE 가 올 수 있음

OpenGL 버전이 3.2 이하면 반드시 GLFW_OPENGL_ANY_PROFILE을 사용해야 함.

 

glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE)

현재 OpenGL 버전에서 deprecated된 함수들을 삭제할지 여부

GL_TRUE / GL_FALSE 가 올 수 있음

 

glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer)

https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glVertexAttribPointer.xhtml

 

glVertexAttribPointer - OpenGL 4 Reference Pages

 

www.khronos.org

 

 

다른 함수들은 아래 레퍼런스나 구글에 쳐보면 잘 나온다.

https://www.glfw.org/docs/3.3/window_guide.html#GLFW_OPENGL_PROFILE_hint

 

GLFW: Window guide

This guide introduces the window related functions of GLFW. For details on a specific function in this category, see the Window reference. There are also guides for the other areas of GLFW. Window objects The GLFWwindow object encapsulates both a window an

www.glfw.org

 

실행 화면

 

소스코드

#include <GLFW/glfw3.h>

int main(void)
{
    GLFWwindow* window;

    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }

    /* Make the window's context current */
    glfwMakeContextCurrent(window);

    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        /* Render here */
        glClear(GL_COLOR_BUFFER_BIT);

        /* Swap front and back buffers */
        glfwSwapBuffers(window);

        /* Poll for and process events */
        glfwPollEvents();
    }

    glfwTerminate();
    return 0;
}

 

우선 OpenGL 개발을 위한 유명한 오픈소스 라이브러리인 GLFW와 GLES를 연동한다.

 

1. GLFW 설치

https://www.glfw.org/download.html

 

Download

GLFW source code and binary distribution download links.

www.glfw.org

위 사이트에서 원하는 버전의 Windows pre-compiled binaries를 다운로드한다.

나는 Visual studio에서 x86으로 컴파일을 할 것이기 때문에 32-bit Windows binaries를 다운로드했다.

 

2. GLES 설치

http://glew.sourceforge.net/

 

GLEW: The OpenGL Extension Wrangler Library

The OpenGL Extension Wrangler Library The OpenGL Extension Wrangler Library (GLEW) is a cross-platform open-source C/C++ extension loading library. GLEW provides efficient run-time mechanisms for determining which OpenGL extensions are supported on the tar

glew.sourceforge.net

위 사이트에서 Windows 32-bit and 64-bit binary를 다운로드한다.

 

3. Visual Studio 세팅

정적 라이브러리를 프로젝트에서 사용할 수 있게 연동해준다.

  • <프로젝트 세팅 → C/C++ → 일반 → 추가포함 디렉터리>에 include(헤더파일) 경로를 추가해준다.

 

  • <프로젝트 세팅 → 링커 → 일반 → 추가 라이브러리 디렉터리>에 lib파일 경로를 추가해준다.

 

 

  • <프로젝트 세팅 → 링커 → 입력 → 추가 종속성>에 사용할 lib파일 이름을 추가해준다.

 

참고한 블로그

https://gongdolhoon.tistory.com/entry/1-OpenGL-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0

 

[C++/Modern OpenGL] 1. OpenGL 개발 환경 세팅하기

2. OpenGL 개발 환경 세팅하기  "시작이 반이다. (Well begun is half done.)" - Aristotle  라이브러리를 사용한 경험이 잦은 사람들은 어떤 라이브러리를 가져올 때, 세팅하는 것이 어렵지는 않을 것입니다.

gongdolhoon.tistory.com

 

+ Recent posts