해상도와 타이틀을 설정하여 창 객체 생성
창을 끄라는 명령이 나오기 전까지 while 무한루프를 돌며 프로그램을 업데이트하고 렌더링
루프가 끝나면 GLFW 정리 및 종료
#define GLEW_STATIC
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <vector>
using namespace glm;
void render(GLFWwindow* window);
void init();
int main(void)
{
if (!glfwInit()) exit(EXIT_FAILURE); // glfw 핵심 객체 초기화
glfwWindowHint(GLFW_SAMPLES, 8); // 생성할 Window의 기본 설정
GLFWwindow* window = glfwCreateWindow(640, 480, "Hello", NULL, NULL); // 창 객체 생성
glfwMakeContextCurrent(window); // 생성된 창에 대응되는 opengl 컨텍스트 객체 생성
glewInit();
glfwSwapInterval(1); // 스왑 간격 : 0 설정하면 fps 제한X, 1 설정하면 fps 제한 60
while (!glfwWindowShouldClose(window)) { // 창이 닫히기 전까지 무한루프
render(window);
glfwSwapBuffers(window);
glfwPollEvents(); // 대기 중인 이벤트 처리
}
glfwDestroyWindow(window); // 루프가 끝났으므로 종료
glfwTerminate();
}
void render(GLFWwindow* window) {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(0.1, 0.1, 0.1, 0);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, triangles.size()*3, GL_UNSIGNED_INT, 0);
}
readfile
함수로 obj
파일 로드Rootnode
를 통해 모든 부모, 자식 노드에 접근하여 recursive하게 processMesh
함수 호출#pragma once
#ifndef objLoader_h
#define objLoader_h
#include <glm/glm.hpp>
#include <vector>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
std::vector<glm::vec3> vertices;
std::vector<glm::u32vec3> triangles;
void processMesh(aiMesh* mesh, const aiScene* scene)
{
// mesh's vertex
vertices.resize(mesh->mNumVertices);
normals.resize(mesh->mNumVertices);
texcoords.resize(mesh->mNumVertices);
for (unsigned int i = 0; i < mesh->mNumVertices; ++i)
{
glm::vec3 vector;
// position
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
vertices[i] = vector;
// normal . . .
// texture coordinate . . .
}
// mesh's face (triangle)
for (unsigned int i = 0; i < mesh->mNumFaces; ++i)
{
aiFace face = mesh->mFaces[i];
triangles.push_back(glm::u32vec3(face.mIndices[0], face.mIndices[1], face.mIndices[2]));
}
}
void processNode(aiNode* node, const aiScene* scene)
{
for (unsigned int i = 0; i < node->mNumMeshes; ++i) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
processMesh(mesh, scene);
}
for (unsigned int i = 0; i < node->mNumChildren; ++i) {
processNode(node->mChildren[i], scene);
}
}
bool loadObj(const std::string& filePath)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(filePath, aiProcess_Triangulate | aiProcess_FlipUVs);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << "ERROR::ASSIMP::" << importer.GetErrorString() << std::endl;
return 0;
}
processNode(scene->mRootNode, scene);
}
#endif
loadObj
함수를 호출하여 모델을 로드하고, 받아온 mesh 데이터를 버퍼에 저장glDrawElements
함수로 렌더링. . .
GLuint vertexBuffer = 0; // 버퍼 ID (GLuint: Opengl의 unsigned long형)
GLuint vertexArray = 0; // 버텍스어레이 ID
GLuint elementBuffer = 0;
Program program;
void init() {
if (!loadObj("LPS_Head.obj")) {
std::cerr << "Failed to load the model!" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
program.loadShaders("shader.vert", "shader.frag");
// <버텍스 정보 저장>
// 1. Vertex Buffer Object (VBO)
glGenBuffers(1, &vertexBuffer); // 버퍼 1개 생성
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer); // 사용할 버퍼 선언(바인딩; 하이라이팅)
glBufferData(GL_ARRAY_BUFFER, vertices.size()*sizeof(vec3), vertices.data(), GL_STATIC_DRAW); // 버퍼에 버텍스 정보 데이터 저장
// 2. Vertex Array Object (VAO)
glGenVertexArrays(1, &vertexArray); // 버텍스어레이 1개 생성
glBindVertexArray(vertexArray); // 사용할 버텍스어레이 선언
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glEnableVertexAttribArray(0); // 버텍스어레이 안에 버텍스 속성을 담을 0번 공간 활성화
glVertexAttribPointer(0, 3, GL_FLOAT, 0, 0, 0); // 활성화한 속성을 가진 버퍼를 0번 공간에 저장 (버텍스 당 숫자 3개 x, y, z)
// 3. Element Array Buffer
glGenBuffers(1, &elementBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, triangles.size() * sizeof(u32vec3), triangles.data(), GL_STATIC_DRAW);
}
void render(GLFWwindow* window) {
int width, height;
glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(0.1, 0.1, 0.1, 0);
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program.programID);
GLuint colorLocation = glGetUniformLocation(program.programID, "color");
glUniform4fv(colorLocation, 1, value_ptr(vec4(1, 1, 0, 1)));
glBindVertexArray(vertexArray);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementBuffer);
glDrawElements(GL_TRIANGLES, triangles.size()*3, GL_UNSIGNED_INT, 0);
}
#version 150 core
uniform vec4 color;
out vec4 out_Color;
void main(void)
{
out_Color = color;
}
Assimp로 모델 데이터는 잘 받아온 것 같은데 모델이 렌더링되지 않는 문제
렌더링 과정의 문제인지 확인하기 위해 삼각형을 그려봤고, 삼각형도 뜨지 않음
glUseProgram(program.programID);
GLuint colorLocation = glGetUniformLocation(program.programID, "color");
glUniform4fv(colorLocation, 1, value_ptr(vec4(1, 1, 0, 1)));
color
입력 데이터 전달)삼각형은 뜨지만, obj 모델은 여전히 안뜸
loadObj.h
의 processMesh()
함수에서 버텍스 정보를 가질 벡터들을 버텍스 수 만큼 resize 했는데 push_back
으로 버텍스 정보들을 넣어줌.......(바보) 정작 필요한 곳에 데이터들이 들어가지 못함
인덱싱으로 정보들을 넣어주고 렌더링 성공
void processMesh(aiMesh* mesh, const aiScene* scene)
{
// 버텍스 정보 벡터 resize
vertices.resize(mesh->mNumVertices);
normals.resize(mesh->mNumVertices);
texcoords.resize(mesh->mNumVertices);
for (unsigned int i = 0; i < mesh->mNumVertices; ++i)
{
glm::vec3 vector;
vector.x = mesh->mVertices[i].x;
vector.y = mesh->mVertices[i].y;
vector.z = mesh->mVertices[i].z;
// vertices.push_back(vector);
vertices[i] = vector;
. . .