반응형
3D 게임 프로젝트 시작
이제까지 학습한 3D 그래픽 기법을 활용하여 간단한 3D 게임 프로젝트를 시작하겠습니다. 오늘부터 3일간에 걸쳐 3D 게임 프로젝트를 단계별로 완성해 나갈 것입니다. 첫 번째 단계로 게임의 기본 구조를 설정하고, 간단한 3D 장면을 렌더링해보겠습니다.
프로젝트 설정
프로젝트 구조
먼저, 프로젝트 디렉토리 구조를 설정합니다.
3DGameProject/
|-- include/
|-- src/
| |-- main.cpp
| |-- Shader.h
| |-- Shader.cpp
|-- resources/
| |-- textures/
| |-- models/
|-- CMakeLists.txt
CMake 설정
프로젝트를 빌드하기 위해 CMake 설정 파일을 작성합니다.
cmake_minimum_required(VERSION 3.10)
project(3DGameProject)
set(CMAKE_CXX_STANDARD 11)
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(glfw3 REQUIRED)
include_directories(${OPENGL_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS} include)
add_executable(3DGameProject src/main.cpp src/Shader.cpp)
target_link_libraries(3DGameProject ${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} glfw)
Shader 클래스 작성
셰이더를 관리하기 위한 Shader
클래스를 작성합니다. 이 클래스는 셰이더를 로드하고 컴파일하며, OpenGL 셰이더 프로그램을 생성하는 기능을 제공합니다.
Shader.h
#ifndef SHADER_H
#define SHADER_H
#include <GL/glew.h>
#include <string>
class Shader {
public:
GLuint Program;
Shader(const GLchar* vertexPath, const GLchar* fragmentPath);
void use();
};
#endif
Shader.cpp
#include "Shader.h"
#include <iostream>
#include <fstream>
#include <sstream>
Shader::Shader(const GLchar* vertexPath, const GLchar* fragmentPath) {
std::string vertexCode;
std::string fragmentCode;
std::ifstream vShaderFile;
std::ifstream fShaderFile;
vShaderFile.exceptions(std::ifstream::badbit);
fShaderFile.exceptions(std::ifstream::badbit);
try {
vShaderFile.open(vertexPath);
fShaderFile.open(fragmentPath);
std::stringstream vShaderStream, fShaderStream;
vShaderStream << vShaderFile.rdbuf();
fShaderStream << fShaderFile.rdbuf();
vShaderFile.close();
fShaderFile.close();
vertexCode = vShaderStream.str();
fragmentCode = fShaderStream.str();
} catch (std::ifstream::failure e) {
std::cerr << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl;
}
const GLchar* vShaderCode = vertexCode.c_str();
const GLchar* fShaderCode = fragmentCode.c_str();
GLuint vertex, fragment;
GLint success;
GLchar infoLog[512];
vertex = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex, 1, &vShaderCode, NULL);
glCompileShader(vertex);
glGetShaderiv(vertex, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertex, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
}
fragment = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment, 1, &fShaderCode, NULL);
glCompileShader(fragment);
glGetShaderiv(fragment, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragment, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
}
this->Program = glCreateProgram();
glAttachShader(this->Program, vertex);
glAttachShader(this->Program, fragment);
glLinkProgram(this->Program);
glGetProgramiv(this->Program, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(this->Program, 512, NULL, infoLog);
std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
}
glDeleteShader(vertex);
glDeleteShader(fragment);
}
void Shader::use() {
glUseProgram(this->Program);
}
기본 3D 장면 렌더링
다음으로, OpenGL과 GLFW를 사용하여 간단한 3D 장면을 렌더링하는 코드를 작성합니다.
main.cpp
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include "Shader.h"
// 정점 셰이더 소스 코드
const char* vertexShaderSource = R"glsl(
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
)glsl";
// 프래그먼트 셰이더 소스 코드
const char* fragmentShaderSource = R"glsl(
#version 330 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, TexCoord);
}
)glsl";
int main() {
// GLFW 초기화
if (!glfwInit()) {
std::cerr << "Failed to initialize GLFW" << std::endl;
return -1;
}
// OpenGL 버전 설정 (3.3)
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// 창 생성
GLFWwindow* window = glfwCreateWindow(800, 600, "3D Game Project", NULL, NULL);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
// OpenGL 컨텍스트 설정
glfwMakeContextCurrent(window);
// GLEW 초기화
glewExperimental = GL_TRUE;
if (glewInit() != GLEW_OK) {
std::cerr << "Failed to initialize GLEW" << std::endl;
return -1;
}
// 셰이더 프로그램 생성
Shader ourShader(vertexShaderSource, fragmentShaderSource);
// 정점 데이터
float vertices[] = {
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f
};
unsigned int indices[] = {
0, 1, 3, 1, 2, 3, // 앞
4, 5, 7, 5, 6, 7, // 뒤
0, 1, 5, 0, 4, 5, // 위
2, 3, 7, 2, 6, 7, // 아래
1, 2, 6, 1, 5, 6, // 왼쪽
0, 3, 7, 0, 4, 7 // 오른쪽
};
GLuint VBO, VAO, EBO;
glGenVertexArrays(
1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// 텍스처 로딩
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height;
unsigned char* image = SOIL_load_image("path/to/your/texture.png", &width, &height, 0, SOIL_LOAD_RGB);
if (image) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
glGenerateMipmap(GL_TEXTURE_2D);
} else {
std::cerr << "Failed to load texture" << std::endl;
}
SOIL_free_image_data(image);
glBindTexture(GL_TEXTURE_2D, 0);
// OpenGL 상태 설정
glEnable(GL_DEPTH_TEST);
// 메인 루프
while (!glfwWindowShouldClose(window)) {
// 입력 처리
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, true);
}
// 화면 지우기
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 셰이더 프로그램 사용
ourShader.use();
// 변환 행렬 설정
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -3.0f));
glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f);
GLint modelLoc = glGetUniformLocation(ourShader.Program, "model");
GLint viewLoc = glGetUniformLocation(ourShader.Program, "view");
GLint projectionLoc = glGetUniformLocation(ourShader.Program, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection));
// 텍스처 바인딩
glBindTexture(GL_TEXTURE_2D, texture);
// 객체 그리기
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// 버퍼 교환
glfwSwapBuffers(window);
glfwPollEvents();
}
// 자원 해제
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
결론
오늘은 3D 게임 프로젝트의 기본 구조를 설정하고, 간단한 3D 장면을 렌더링하는 방법을 학습했습니다. 다음 단계에서는 게임에 다양한 기능을 추가하고, 더욱 복잡한 3D 장면을 구현해보겠습니다. 질문이나 추가적인 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Day 25: 3D 게임 프로젝트 시작 (2)"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 게임 개발 시리즈' 카테고리의 다른 글
[C++ 게임 개발 시리즈] Day 26: 3D 게임 프로젝트 시작 (3) (0) | 2024.08.01 |
---|---|
[C++ 게임 개발 시리즈] Day 23: 3D 모델링과 텍스처링 (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 21: 적 캐릭터와 NPC의 AI 구현 (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 22: 3D 그래픽 기초 (0) | 2024.08.01 |
[C++ 게임 개발 시리즈] Day 19: 경로 찾기 알고리즘 (A* 알고리즘) (0) | 2024.08.01 |