glm::vec3 Memory Alignment

2024-01-21 glm::vec3 放入结构体中的对其问题

Posted by CaoFulei on Sunday, January 21, 2024

介绍

在OpenGL编程中,与顶点数据的交互是非常常见的操作。在C++中,通常会使用GLM库提供的数据结构,如glm::vec3,来表示顶点数据。然而,内存对齐问题可能会影响到这种交互,特别是在涉及到结构体的内存布局时。本教程将探讨在OpenGL中如何处理顶点数据,并对比在加入GLM宏定义和不加入GLM宏定义的情况下的内存大小差异,同时提供相应的Shader代码。

当你在使用GLM库时,可能会遇到内存对齐的问题,特别是在与其他库或系统进行交互时。GLM提供了一个宏定义GLM_FORCE_ALIGNED,它可以强制GLM库使用对齐内存分配。在这个教程中,我们将讨论如何使用GLM_FORCE_ALIGNED宏,并将其应用到我们之前的示例中。

GLM_FORCE_ALIGNED宏的作用

GLM_FORCE_ALIGNED宏可以强制GLM库使用对齐内存分配,以确保GLM的向量和矩阵类型与OpenGL兼容。通过使用对齐内存分配,可以避免由于内存对齐不一致而导致的问题,特别是在与底层图形库(如OpenGL)进行交互时。

将GLM_FORCE_ALIGNED宏应用到示例中

首先,在包含GLM头文件之前定义GLM_FORCE_ALIGNED宏。

#define GLM_FORCE_ALIGNED
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

这将强制GLM库使用对齐内存分配。

接下来,我们将GLM的向量和矩阵类型应用到我们之前的顶点数据结构中。

struct Vertex
{
    glm::vec3 vertex;
    DWORD color;
    glm::vec2 tex;
};

现在,我们的顶点数据结构中使用了GLM的向量类型,并且由于我们定义了GLM_FORCE_ALIGNED宏,GLM将确保这些向量类型使用了对齐内存分配。

不加宏定义的情况

首先,我们来看看在不加入GLM宏定义的情况下,顶点数据结构的内存大小是多少。假设我们有以下的顶点数据结构:

struct Vertex
{
    glm::vec3 vertex;
    DWORD color;
    glm::vec2 tex;
};

接下来,我们可以使用sizeof操作符来获取顶点数据结构的内存大小:

size_t vertexSize = sizeof(Vertex);

在这个例子中,vertexSize的值是24字节。这是因为glm::vec3glm::vec2分别占用12字节和8字节,DWORD占用4字节,所以总共是24字节。

然后,我们初始化一组顶点数据:

using VertexArray = std::vector<Vertex>;

VertexArray vertices = {
    {{-0.5f, -0.5f, 0.0f}, 0xFF0000, {0.0f, 0.0f}},
    {{0.5f, -0.5f, 0.0f}, 0x00FF00, {1.0f, 0.0f}},
    {{0.0f, 0.5f, 0.0f}, 0x0000FF, {0.5f, 1.0f}}
};

// 创建顶点缓冲对象
GLuint VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW);

在这个示例中,我们使用了glGenBuffers、glBindBuffer和glBufferData函数来创建和填充顶点缓冲区对象。顶点缓冲区对象存储了顶点数据,并可以通过glVertexAttribPointer函数来指定顶点数据的布局。

DWORD :GL_UNSIGNED_BYTE, GL_TRUE

// 指定顶点属性
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, vertex));
glEnableVertexAttribArray(0);

glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, color));
glEnableVertexAttribArray(1);

glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, tex));
glEnableVertexAttribArray(2);

接下来,我们需要创建一个Vertex Shader和一个Fragment Shader来处理这些顶点数据。Shader代码如下:

Vertex Shader:

#version 330 core

layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texCoord;

out vec4 vertexColor;
out vec2 texCoordOut;

void main()
{
    gl_Position = vec4(position, 1.0);
    vertexColor = color;
    texCoordOut = texCoord;
}

Fragment Shader:

#version 330 core

in vec4 vertexColor;
in vec2 texCoordOut;

out vec4 FragColor;

void main()
{
    FragColor = vertexColor;
}

加入GLM宏定义的情况

现在,让我们来看看如果我们加入GLM宏定义#define GLM_FORCE_ALIGNED后会发生什么。首先,在顶点数据结构定义之前加入这个宏定义:

#define GLM_FORCE_ALIGNED
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

然后,我们再次计算顶点数据结构的内存大小:

size_t vertexSizeAligned = sizeof(Vertex);

在加入GLM宏定义后,vertexSizeAligned的值变为32字节。这是因为GLM强制使用对齐内存分配,导致每个glm::vec3和glm::vec2都被对齐到16字节和12字节的边界,而DWORD占用4字节,因此总大小变为32字节。

总结

通过使用GLM_FORCE_ALIGNED宏,我们可以确保GLM库的向量和矩阵类型使用了对齐内存分配,从而提高了与其他库和系统的兼容性。在本教程中,我们介绍了如何使用这个宏,并将其应用到之前的示例中,以确保顶点数据结构与OpenGL兼容。

「真诚赞赏,手留余香」

Caofulei

真诚赞赏,手留余香

使用微信扫描二维码完成支付