使用std :: vector和glm :: vec3的OpenGL

5
我遇到了以下问题。
我已经将 8 个glm::vec3加载到std::vector中,如下所示:
std::vector <glm::vec3> vertices;

返回值: 0.250000 -0.250000 -0.250000
0.250000 -0.250000 0.250000
-0.250000 -0.250000 0.250000
-0.250000 -0.250000 -0.250000
0.250000 0.250000 -0.250000
0.250000 0.250000 0.250000
-0.250000 0.250000 0.250000
-0.250000 0.250000 -0.250000
如果:
for(int i{0}; i<8; i++){
    std::cout<<"\n";
    for(int j{0}; j<3; j++){
    std::cout<<vertices[i][j]<<" ";
    }
}

当我将以下代码传递到OpenGL时,
glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vertices.size(), &vertices[0],  GL_DYNAMIC_DRAW);  

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 

glBindVertexArray(buffer);  

我的着色器程序已加载并打开了窗口,但是没有立方体。
对第一行进行轻微修改,
glBufferData(GL_ARRAY_BUFFER, sizeof(vert), &vert, GL_DYNAMIC_DRAW); //Here

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

glBindVertexArray(buffer); 

从中提取向量时,
const GLfloat vert[9] =
{-0.5,-0.5, 0.0,
  0.0, 0.5, 0.0,
  0.5,-0.5, 0.0};

并且一个漂亮的红色三角形被绘制在屏幕上。

我的问题:在glm中是否可以与向量容器结合使用?如果可以,如何实现?
我的假设:glVertexAttribPointer函数正在从顶点容器的起始地址按顺序读取。顶点容器的元素在我的内存中是分散的。


可以使用OpenGL的类型与glm类型进行交互操作,我猜想方块或者绘制方式存在其他问题。因为你提到使用浮点数数组工作正常的三角形顶点,你可以尝试在那里使用glm::vec3数组,看看会发生什么。 - Twinklebear
@Twinklebear,我之前绘制的方式只适用于二维对象。我花了2秒钟解决了这个问题,选择使用glDrawElements和我的cube.obj文件中的面来连接点。 - a_learner
1
那你为什么有一个VAO却不用它来绘制呢?没有更多的代码很难知道发生了什么,但这里展示的代码片段表明你正在错误地使用VAO。 - Reto Koradi
也许我还不太理解这一切是如何工作的。我在主函数中创建了一个VAO GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao);,而我在'glBindVertexArray(buffer);中绑定的是VBO,因为我认为由于glBindBuffer(GL_ARRAY_BUFFER, vbo);glBufferData(GL_ARRAY_BUFFER, sizeof(vert), &vert, GL_DYNAMIC_DRAW);`的GL_ARRAY_BUFFER参数目标,它已经保存到了VAO中。如果不是这样,那么为什么它会绘制我想要的对象呢?我还没有弄清楚着色器。我只看到一个红色的正方形。 - a_learner
我看不出那行代码出现问题的原因。你为什么不拿三角形的工作示例,只用std::vector<glm::vec3>替换数组呢? - Quentin
显示剩余2条评论
4个回答

2
在您的glBufferData()中,&vertices[0]可能应该是&vertices[0].x
这是因为&vertices[0]指向一个glm::vec3,但您希望它指向一个float
因为这是OpenGL所期望的。

它确实指向一个glm::vec3。我尝试了你的方法,也尝试了&vertices[0][0]。但是,它仍然无法渲染。 - a_learner
@a_learner 你觉得在调用 glBufferDatavertices 可能被销毁吗? - Axalo
不,vertices是从main()调用的对象中的public:向量容器。我在主函数中使用了一个for循环检查了vertices,之前已经通过一个公共函数glBufferData调用了与vertices同一类下的另一个公共函数。 - a_learner
1
我看到你的代码了。std::vector<GLfloat> vv(&vertices[0].x, &vertices[0].x + sizeof(glm::vec3) * vertices.size()); 给了我一个完全复制 vertices 的副本。然后我在该类的 public 下面创建了一个副本 std::vector <GLfloat> v,这样一来,当我离开函数调用时它就不会被销毁了。我使用 glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3)*vertices.size(), &v, GL_DYNAMIC_DRAW); 然后它就画出了东西! 它不完全是一个立方体,但它真的有点像! - a_learner
@a_learner 是的,通常使用浮点数数组来完成。不过 std::vector 也可以。 - Axalo
显示剩余2条评论

1

我认为您不能将复杂类型传递到着色器中。我通常会创建一个包含位置的浮点数组的结构体:

struct vertex{
    GLfloat positions[3];
};

然后在你的代码中使用:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertex) * vertices.size(),
             &vertices[0],  GL_DYNAMIC_DRAW);  

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); 

glBindVertexArray(buffer);  

这是一个有趣的替代方案,但OpenGL肯定允许您将glm :: vec3发送到着色器。首先,它们本质上是小型浮点数数组,其次,GLM是OpenGL数学库,那么为什么他们不设计它与他们的着色器兼容呢? - a_learner
该方法允许将每个顶点的所有数据进行整合,例如纹理坐标和法向量。 - eklukovich
是的,我知道你的方法是比较流行的其中一种。 - a_learner
1
只要复杂类型是设计为这样做的,您就可以传递它们。而GLM库的设计就是为了支持这种类型的使用。因此,重新发明向量和矩阵的自己类别实际上没有任何意义。GLM不是OpenGL的一部分,也不来自Khronos组织的任何角落。它是基于GLSL规范的外部工具。可能会有错误或某些未定义的行为,但它已经存在多年,并被证明非常稳定可靠。 - Mars

0

C++11的std::vector有一个内置函数data(), 它返回指向底层数据的指针,使得[data(), data() + size()]是向量的有效范围。

此外,在处理glm :: ivec类型的数组时,您不需要请求任何数据指针。以下代码示例是完全有效的OpenGL代码,并且可以无问题地呈现:

glm::vec3 vertices[] = {
    glm::vec3(0.0f,  0.0f, 0.0f),
    glm::vec3(0.0f,  1.0f, 0.0f),
    glm::vec3(1.0f,  1.0f, 0.0f)
};
int sizeVertices = sizeof(vertices) / sizeof(glm::vec3);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// ...
glDrawArrays(GL_LINES, 0, sizeVertices);

0

你是否启用了背面剔除?因为如果你没有设置视图矩阵或者相机在立方体内部,那么你可能只能看到背面,而这些背面可能被剔除。而在你的第二个例子中,三角形正面朝向你,因此是可见的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接