迭代顶点缓冲区

Posted

技术标签:

【中文标题】迭代顶点缓冲区【英文标题】:Iterate Vertex Buffer 【发布时间】:2013-05-04 06:50:52 【问题描述】:

我正在尝试模拟 OpenGL 的 GL_POINT 进行调试和逆向工程 OpenGL。我正在尝试给定它的指针、索引缓冲区指针和步幅。

所以我做了什么:

我连接了一个使用 OpenGL 的应用程序。 我使用 gDebugger 监控调用 (AMD 为调试创建的应用程序)

要渲染单个模型,调用是:

glPushMatrix()
glViewport(4, 165, 512, 334)
glMultMatrixf(1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
26880, -741, 26368, 1)

glGenBuffersARB(1, 0x0A2B79D4)
glBindBufferARB(GL_ARRAY_BUFFER, 15)
glBufferDataARB(GL_ARRAY_BUFFER, 17460, 0x0C85DE1C, GL_STATIC_DRAW)
glGenBuffersARB(1, 0x0A2B79D4)
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 16)
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, 8946, 0x0C85DE1C, GL_STATIC_DRAW)
glBindBufferARB(GL_ARRAY_BUFFER, 0)
glVertexPointer(3, GL_FLOAT, 12, 0x31CB24C9)
glEnableClientState(GL_VERTEX_ARRAY)
glDisableClientState(GL_NORMAL_ARRAY)
glBindBufferARB(GL_ARRAY_BUFFER, 15)
glColorPointer(4, GL_UNSIGNED_BYTE, 12, 0x00000000)
glEnableClientState(GL_COLOR_ARRAY)
glTexCoordPointer(2, GL_FLOAT, 12, 0x00000004)
glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glDrawElements(GL_TRIANGLES, 4473, GL_UNSIGNED_SHORT, 0x00000000)
glPopMatrix()

我挂钩了每个调用并将所有参数存储到一个类和一些变量中。

typedef struct  //A struct to hold information about every buffer the application uses.

    GLint ID;
    GLsizei Size;
    GLboolean Reserved;
    GLboolean Bound;
    GLenum Type, Usage;
    uint32_t CheckSum;
    const GLvoid* BufferPointer;
 BufferObject;


BufferObject CurrentBuffer;  //Keep track of the currently bound buffer.
std::vector<BufferObject> ListOfBuffers;  //A list of all buffers used in the application.



//Detours the OpenGL function so that it calls this one first before calling the original one. (OpenGL call interception.)
void HookglVertexPointer(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)

    if ((size == 3) && (pointer != nullptr) && type == GL_FLOAT) //A model is rendering..
    
        ModelRendering = true;
        CurrentModel.Stride = stride;
        CurrentModel.VertexPointer = pointer; //Store the pointer.
        ListOfModels.push_back(CurrentModel); //Store the model.
    

    (*original_glVertexPointer) (size, type, stride, pointer); //Call the original function.


//Hook the drawing function and get each vertex being rendered.
void HookglDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)

    Model* ModelPtr = &ListOfModels.back();

    if (ModelPtr != nullptr)
    
        for (int I = 0; I < count / 3; ++I) //So for every triangle, I want to get the vertex of it and store it in my Vertices vector..
        
            //This needs to somehow use the stride to get the right vertex.
            //Perhaps CurrentBuffer.BufferPointer instead of ModelPtr->VertexPointer.
            int X = *reinterpret_cast<const GLfloat*>(reinterpret_cast<const char*>(ModelPtr->VertexPointer) * I);
            int Y = *reinterpret_cast<const GLfloat*>(reinterpret_cast<const char*>(ModelPtr->VertexPointer) * I + 1);
            int Z = *reinterpret_cast<const GLfloat*>(reinterpret_cast<const char*>(ModelPtr->VertexPointer) * I + 2);
            ModelPtr->Vertices.push_back(Vector3D(X, Y, Z));
        
    
    (*original_glDrawElements) (mode, count, type, indices);  //call the original function.

如果有的话,如何获取每个三角形的顶点:

VBO 指针。 大步前进。 索引指针。

【问题讨论】:

我看不出这与 GL_POINTS 有什么关系。 GL_POINT 在您将它与 glDrawElements 一起使用时会执行此操作。如果我设置 GL_FILL,它会填充整个模型。如果我设置 GL_POINTS,它只会显示每个顶点。我想得到每个顶点,就像函数在使用 GL_POINTS 时所做的那样。我想我正试图弄清楚 gl_drawelements 是如何工作并模拟它的。 我仍然对这与GL_POINTS 渲染有什么关系感到困惑。他们正在使用GL_TRIANGLES。您是在谈论 多边形模式,还是在谈论传递给绘图函数的原始类型? 【参考方案1】:

如果有的话,如何获取每个三角形的顶点:

VBO 指针。 大步前进。 索引指针。

你不能。

缓冲区对象没有指针glBufferDataglBufferSubData 复制 数据从给定的指针到缓冲区对象存储。与所有不以“指针”一词结尾的 OpenGL 函数一样,after the execution of these functions, the application is free to do whatever it wants with them。 OpenGL 不保留这些指针。因此,你也不应该。

如果您想跟踪存储在缓冲区对象中的内存,您将不得不自己分配内存并自己进行复制。当glBufferDataglBufferSubData 调用通过时,您将不得不将该指针中的数据复制到您的内部存储中。如果用户映射一个缓冲区进行写入,您将不得不等待缓冲区被取消映射,然后使用glGetBufferSubData 从缓冲区复制数据。

它不会很快。

此外,如果您打算渲染顶点数据,您需要的不仅仅是步幅。你需要类型;假设用户只使用GL_FLOAT 是一个非常糟糕的假设(除非您希望您的代码是特定于应用程序的)。

无论如何,您都在处理一个行为不端的应用程序。它似乎将缓冲区对象用于 some 属性(例如glColorPointer),而不将它们用于其他属性(glVertexPointer)。这会让你的工作更难。

您基本上需要做 OpenGL 所做的事情。对于每个属性,您需要记录类型、步幅、规范化和给定的“指针”。但是您需要检查缓冲区当前是否绑定到GL_ARRAY_BUFFER(这意味着您需要停止假装一次只能绑定一个缓冲区。您需要跟踪绑定到每个不同目标的内容)。

如果在调用“指针”函数之一时缓冲区绑定到GL_ARRAY_BUFFER,那么这意味着给定的“指针”不是指针;它是相对于缓冲区对象开头的字节偏移量。因此,您需要存储“指针”在调用函数时绑定到GL_ARRAY_BUFFER 的缓冲区对象。如果那里没有绑定缓冲区,则该指针实际上是一个真正的内存指针,应用程序必须保持活动状态,只要它尝试使用它进行渲染。

在渲染时,对于每个属性,您要么使用属性的指针,要么使用缓冲区对象 + 偏移量来计算缓冲区对象数据的开始位置。您可以使用它来访问缓冲区对象数据的副本。无论哪种方式,您都解析为指针。然后,您使用类型和规范化来决定如何读取数据,并使用步幅从一个顶点到下一个顶点。

【讨论】:

啊,我明白了。我已经完成了第一部分。我从传递给 glBufferData 和 SubData 的指针中复制了数据,并将其存储在我的 vector ListOfBuffers 中。我没有存储诸如 GL_ARRAY_BUFFER 之类的类型,因为我只存储了 GL_ARRAY_BUFFER 类型的缓冲区。我现在将全部存储。我不知道如何获得规范化或使用它读取数据,但我会查一下。如果它与数学课中的相同,那么我想我将 X 除以长度,这样向量的长度就是一。

以上是关于迭代顶点缓冲区的主要内容,如果未能解决你的问题,请参考以下文章

顶点以及顶点缓冲区

在 GLSL 顶点着色器中,您可以访问索引缓冲区中顶点的索引,而不仅仅是顶点缓冲区吗?

Swizzling 顶点数组、顶点缓冲区对象和着色器

顶点和纹理坐标的缓冲区大小不同?

绑定到“顶点数组对象”后,我应该删除“顶点缓冲区对象”吗?

Directx 11 - 是来自顶点缓冲区的所有顶点都推送到顶点着色器还是只是索引的顶点?