网站首页 > 知识剖析 正文
开发环境
- Windows 10
- Visual Studio Community 2022
前言
当使用建模工具对物体建模的时候,艺术家通常不会用单个形状创建出整个模型。通常每个模型都由几个子模型/形状组合而成。组合模型的每个单独的形状就叫做一个网格(Mesh)。比如说有一个人形的角色:艺术家通常会将头部、四肢、衣服、武器建模为分开的组件,并将这些网格组合而成的结果表现为最终的模型。一个网格是我们在OpenGL中绘制物体所需的最小单位(顶点数据、索引和材质属性)。一个模型(通常)会包括多个网格。
通过使用Assimp,我们可以加载不同的模型到程序中,但是载入后它们都被储存为Assimp的数据结构。我们最终仍要将这些数据转换为OpenGL能够理解的格式,这样才能渲染这个物体。
网格(Mesh)
网格(Mesh)代表的是单个的可绘制实体,一个网格要想被绘制出来,至少需要一系列的顶点,每个顶点最少包含一个位置向量,以及包含用于索引绘制的索引。
我们定义一个最简单的顶点结构:
struct Vertex
{
glm::vec3 Position;
};
网格类的定义:
Mesh.h
class Mesh
{
public:
/// <summary>
/// 顶点数组
/// </summary>
std::vector<Vertex> vertices;
/// <summary>
/// 索引数组
/// </summary>
std::vector<unsigned int> indices;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="vertices">顶点数组</param>
/// <param name="indices">索引数组</param>
Mesh(std::vector<Vertex> vertices, std::vector<unsigned int>indices);
/// <summary>
/// 绑定(绘制)
/// </summary>
void Bind() const;
/// <summary>
/// 解绑(清理)
/// </summary>
void Unbind() const;
private:
unsigned int m_VBO, m_IBO;
void setupMesh();
};
Mesh.cpp
Mesh::Mesh(std::vector<Vertex> vertices, std::vector<unsigned int>indices)
{
this->vertices = vertices;
this->indices = indices;
setupMesh();
}
void Mesh::setupMesh()
{
// 顶点缓存对象
glGenBuffers(1, &m_VBO);
glBindBuffer(GL_ARRAY_BUFFER, m_VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);
// 索引缓存对象
glGenBuffers(1, &m_IBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
// 位置属性
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0);
}
void Mesh::Bind() const
{
// 绘制网格
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
}
void Mesh::Unbind() const
{
// 删除缓存对象
glDeleteBuffers(1, &m_VBO);
glDeleteBuffers(1, &m_IBO);
}
项目实例
1.新建一个C++项目:11_Mesh,并设置为启动项目。
2.配置项目环境
- 配置 GLFW:参考【LearnOpenGL】01.创建窗口
- 配置 GLEW:参考【LearnOpenGL】03.配置GLEW
- 导入 glm 库
- 导入 stb_image 库
- 配置 Assimp:参考【LearnOpenGL】10.Assimp构建和导入
- 拷贝 Shader 类
- 拷贝 Texture2D 类
3.文件结构
主函数
简单的绘制一个由2个三角形组成的长方形:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include "src/Mesh.h"
#include <vector>
const unsigned int screen_width = 640;
const unsigned int screen_height = 480;
Mesh* mesh;
void init() {
// 顶点数据
std::vector<Vertex> vertices = {
{glm::vec3(-0.5f, -0.5f, 0.0f)},
{glm::vec3(-0.5f, 0.5f, 0.0f)},
{glm::vec3( 0.5f, 0.5f, 0.0f)},
{glm::vec3( 0.5f, -0.5f, 0.0f)}
};
// 绘制顶点的顺序
std::vector<unsigned int> indices = {
0, 1, 2, // 第一个三角形的顶点数组下标
2, 0, 3 // 第二个三角形的顶点数组下标
};
mesh = new Mesh(vertices, indices);
}
void display() {
// 绘制
mesh->Bind();
}
void clear() {
mesh->Unbind();
}
// main
int main(void)
{
GLFWwindow* window;
/* Initialize the library */
if (!glfwInit())
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(screen_width, screen_height, "Mesh", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window);
// glew init
if (glewInit() != GLEW_OK) {
std::cout << "glew init error!" << std::endl;
}
// print opengl version
std::cout << "OpenGL version :" << glGetString(GL_VERSION) << std::endl;
/* init */
init();
/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
glClear(GL_COLOR_BUFFER_BIT);
/* display */
display();
/* Swap front and back buffers */
glfwSwapBuffers(window);
/* Poll for and process events */
glfwPollEvents();
}
glfwTerminate();
/* clear */
clear();
return 0;
}
运行结果:
从代码上看,我们把处理顶点数据都封装在Mesh类的setupMesh方法中,使得主函数代码更新简洁清晰。
GitHub[作揖]
https://github.com/zGameDeveloper/LearnOpenGL/tree/main/Project/11_Mesh
猜你喜欢
- 2025-01-02 界面交互篇:个人中心页布局样式与逻辑交互开发
- 2025-01-02 Python 开发Word转PDF工具实现
- 2025-01-02 程序员用Python实现自动化控制键盘和鼠标
- 2025-01-02 JSX和RN样式以及和web的不同之处
- 2025-01-02 原神增大视野范围方法 原神怎么增加可视范围
- 2025-01-02 137.Python——PySide6:QInputDialog输入对话框的创建与使用
- 2025-01-02 科目二倒车入库模拟机程序代码
- 2025-01-02 用 Python 和 Pygame 实现一个图形界面的俄罗斯方块小游戏
- 2025-01-02 软件测试|超好用超简单的Python GUI库——tkinter(二)
- 2025-01-02 红色警戒轻松搞定高分辨率全屏
- 最近发表
-
- jQuery EasyUI使用教程:创建展开行详细编辑表单的CRUD应用
- CSDN免登陆复制代码的几种方法(csdn扫码登录怎么实现的)
- LayUi提高-Select控件使用(layui form select)
- 用 Playwright MCP 让 AI 改它自己写的屎山代码
- multiple-select.js中手动设置全选和取消全选
- 前端实现右键自定义菜单(html 自定义右键菜单)
- JavaScript脚本如何断言select下拉框的元素内容?
- 广州蓝景分享—实用的CSS技巧,助你成为更好的前端开发者
- MyBatis-Plus码之重器 lambda 表达式使用指南,开发效率瞬间提升80%
- Go语言之select的使用和实现原理(go select case)
- 标签列表
-
- xml (46)
- css animation (57)
- array_slice (60)
- htmlspecialchars (54)
- position: absolute (54)
- datediff函数 (47)
- array_pop (49)
- jsmap (52)
- toggleclass (43)
- console.time (63)
- .sql (41)
- ahref (40)
- js json.parse (59)
- html复选框 (60)
- css 透明 (44)
- css 颜色 (47)
- php replace (41)
- css nth-child (48)
- min-height (40)
- xml schema (44)
- css 最后一个元素 (46)
- location.origin (44)
- table border (49)
- html tr (40)
- video controls (49)