以下是一个完整的示例,展示如何使用 OpenGL 和 tinyobjloader
库来读取并渲染 OBJ 文件。
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(OpenGL_OBJ_Example)
find_package(OpenGL REQUIRED)
find_package(glfw3 3.3 REQUIRED)
add_subdirectory(tinyobjloader)
add_executable(OpenGL_OBJ_Example main.cpp)
target_link_libraries(OpenGL_OBJ_Example PRIVATE OpenGL::GL glfw tinyobjloader::tinyobjloader)
main.cpp
#include <iostream>
#include <vector>
#include <tiny_obj_loader.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
// 顶点结构体
struct Vertex {
float position[3];
float normal[3];
float texcoord[2];
};
std::vector<Vertex> vertices;
std::vector<unsigned int> indices;
// 加载OBJ文件
bool loadOBJ(const std::string& filepath) {
tinyobj::attrib_t attrib;
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string warn, err;
// 使用tinyobjloader库加载OBJ文件
bool ret = tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filepath.c_str());
if (!warn.empty()) {
std::cout << "警告: " << warn << std::endl;
}
if (!err.empty()) {
std::cerr << "错误: " << err << std::endl;
}
if (!ret) {
return false;
}
// 解析形状中的顶点数据
for (const auto& shape : shapes) {
for (const auto& index : shape.mesh.indices) {
Vertex vertex = {};
vertex.position[0] = attrib.vertices[3 * index.vertex_index + 0];
vertex.position[1] = attrib.vertices[3 * index.vertex_index + 1];
vertex.position[2] = attrib.vertices[3 * index.vertex_index + 2];
if (!attrib.normals.empty()) {
vertex.normal[0] = attrib.normals[3 * index.normal_index + 0];
vertex.normal[1] = attrib.normals[3 * index.normal_index + 1];
vertex.normal[2] = attrib.normals[3 * index.normal_index + 2];
}
if (!attrib.texcoords.empty()) {
vertex.texcoord[0] = attrib.texcoords[2 * index.texcoord_index + 0];
vertex.texcoord[1] = attrib.texcoords[2 * index.texcoord_index + 1];
}
vertices.push_back(vertex);
indices.push_back(indices.size());
}
}
return true;
}
// 渲染函数
void render() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 绑定并绘制模型
// 使用glDrawElements或glDrawArrays函数绘制加载的顶点和索引
glfwSwapBuffers(glfwGetCurrentContext());
}
int main() {
// 初始化GLFW
if (!glfwInit()) {
std::cerr << "初始化GLFW失败" << std::endl;
return -1;
}
// 创建窗口
GLFWwindow* window = glfwCreateWindow(800, 600, "OpenGL OBJ Loader", NULL, NULL);
if (!window) {
std::cerr << "创建GLFW窗口失败" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
// 初始化GLEW
if (glewInit() != GLEW_OK) {
std::cerr << "初始化GLEW失败" << std::endl;
return -1;
}
glEnable(GL_DEPTH_TEST);
// 加载OBJ文件
if (!loadOBJ("path/to/your/model.obj")) {
std::cerr << "加载OBJ文件失败" << std::endl;
return -1;
}
// 渲染循环
while (!glfwWindowShouldClose(window)) {
render();
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
解释
- CMakeLists.txt:配置CMake项目,添加OpenGL和GLFW依赖,并包含
tinyobjloader
库。 - main.cpp:
- 顶点结构体:定义顶点结构体,包含位置、法线和纹理坐标。
- loadOBJ函数:使用
tinyobjloader
库加载OBJ文件,将顶点数据解析到vertices
和indices
向量中。 - render函数:清除缓冲区,并使用OpenGL函数绘制模型。
- main函数:初始化GLFW和GLEW,创建窗口,加载OBJ文件,并进入渲染循环。
这个示例展示了如何使用 tinyobjloader
库来加载一个OBJ文件并在OpenGL中进行渲染。通过GLFW库创建窗口和处理输入,并使用GLEW库加载OpenGL函数。