学习正确使用VBO [英] Learning to use VBOs properly

查看:173
本文介绍了学习正确使用VBO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我一直试图教会自己使用VBOs,以提高我的OpenGL项目的性能,并学习更多的高级东西比固定功能渲染。但我没有找到太多的方式的一个体面的教程;我发现的最好的是分配了大量内存)建议分配4-8MB):

  GLuint WorldBuffer; 
GLuint IndexBuffer;

...

glGenBuffers(1,& WorldBuffer);
glBindBuffer(GL_ARRAY_BUFFER,WorldBuffer);
int SizeInBytes = 1024 * 2048;
glBufferData(GL_ARRAY_BUFFER,SizeInBytes,NULL,GL_STATIC_DRAW);

glGenBuffers(1,& IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexBuffer);
SizeInBytes = 1024 * 2048;
glBufferData(GL_ELEMENT_ARRAY_BUFFER,SizeInBytes,NULL,GL_STATIC_DRAW);

然后将数据上传到缓冲区。请注意,CreateVertexArray()在顶点数据填充传递的位置的向量,每个顶点贡献3个浮点为位置和3个浮点为正常(最困惑的事情之一的各种教程是什么格式,我应该存储和传输我的实际顶点数据;这看起来像一个体面的近似):

  std :: vector< float> * VertArray = new std :: vector< float> ;; 
pWorld-> CreateVertexArray(VertArray);
unsigned short Indice = 0;
for(int i = 0; i {
std :: cout< (* VertArray)[i] << std :: endl;
glBufferSubData(GL_ARRAY_BUFFER,i * sizeof(float),sizeof(float),&((* VertArray)[i]
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,i * sizeof(unsigned short),sizeof(unsigned short),&(Indice));
++ Indice;
}
delete VertArray;
Indice - = 1;

之后,在游戏循环中,我使用这个代码:

  glBindBuffer(GL_ARRAY_BUFFER,WorldBuffer); 
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,IndexBuffer);

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3,GL_FLOAT,0,0);
glNormalPointer(GL_FLOAT,0,0);

glDrawElements(GL_TRIANGLES,Indice,GL_UNSIGNED_SHORT,0);

glDisableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);

我完全诚实 - 我不知道我理解第< c $ c> glVertexPointer()和 glNormalPointer()应该是(stride是以字节为单位的偏移,但 Songho 在值之间使用0字节的偏移量 - 什么?),或者这些参数中的最后一个是什么。初始值被认为是0;但它应该是一个指针。传递一个空指针为了获得数组的第一个坐标/正常值看起来很奇怪。 此家伙使用 BUFFER_OFFSET(0) BUFFER_OFFSET(12),但是当我尝试时,我被告知BUFFER_OFFSET()未定义。



glDrawElements()应该是一个地址,但是Songho使用的地址为0.如果我使用& IndexBuffer 而不是0,我得到一个没有任何渲染的空白屏幕,除了背景。



有人能启发我,或至少指向我的方向的东西,将帮助我想出这一点?谢谢!

解决方案


初始值为0;但它应该是一个指针。


上下文(不是OpenGL的意思)很重要。如果在没有绑定到GL_ARRAY_BUFFER的缓冲区对象的情况下调用其中一个gl * Pointer函数,则它是一个指向客户端进程地址空间的指针。如果缓冲区对象绑定到GL_ARRAY_BUFFER,它是到当前绑定的缓冲区对象的一个​​偏移量(你可能需要BO形成一个虚拟地址空间,gl * Pointer的参数就是指向服务器端地址空间的指针)。



现在让我们来看看你的代码。

  std :: vector< ; float> * VertArray = new std :: vector< float> 

你不应该真的混合STL容器和 new ,了解RAII模式。

  pWorld-> CreateVertexArray(VertArray); 

这是有问题的,因为稍后你会删除VertexArray,不好。

  unsigned short Indice = 0; 
for(int i = 0; i {
std :: cout< (* VertArray)[i] << std :: endl;
glBufferSubData(GL_ARRAY_BUFFER,i * sizeof(float),sizeof(float),&((* VertArray)[i]

您应该使用glBufferSubData提交大量数据,而不是单个数据点。



> glBufferSubData(GL_ELEMENT_ARRAY_BUFFER,i * sizeof(unsigned short),sizeof(unsigned short),&(Indice));

您只是将递增索引传递到GL_ELEMENT_ARRAY_BUFFER,从而枚举顶点。为什么?你可以有这个,没有使用glDrawElements的glDrawArrays实例的额外工作。

  ++ Indice; 
}
delete VertArray;

您正在删除VertArray,因此保留悬空指针。

  Indice  -  = 1; 

为什么不使用循环计数器 i



那么如何解决这个问题呢?像这样:

  std :: vector< float&顶点数组; 
pWorld-> LoadVertexArray(VertexArray); // World :: LoadVertexArray(std :: vector< float>&);

glBufferSubData(GL_ARRAY_BUFFER,0,sizeof(float)* VertexArray-> size(),& VertexArray [0]);

并使用glDrawArrays;当然如果你不枚举顶点,但有一个面子→顶点索引的列表,使用glDrawElements是必须的。


So I've been trying to teach myself to use VBOs, in order to boost the performance of my OpenGL project and learn more advanced stuff than fixed-function rendering. But I haven't found much in the way of a decent tutorial; the best ones I've found so far are Songho's tutorials and the stuff at OpenGL.org, but I seem to be missing some kind of background knowledge to fully understand what's going on, though I can't tell exactly what it is I'm not getting, save the usage of a few parameters.

In any case, I've forged on ahead and come up with some cannibalized code that, at least, doesn't crash, but it leads to bizarre results. What I want to render is this (rendered using fixed-function; it's supposed to be brown and the background grey, but all my OpenGL screenshots seem to adopt magenta as their favorite color; maybe it's because I use SFML for the window?).

What I get, though, is this:

I'm at a loss. Here's the relevant code I use, first for setting up the buffer objects (I allocate lots of memory as per this guy's recommendation to allocate 4-8MB):

GLuint WorldBuffer;
GLuint IndexBuffer;

...

glGenBuffers(1, &WorldBuffer);
glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);
int SizeInBytes = 1024 * 2048;
glBufferData(GL_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW);

glGenBuffers(1, &IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
SizeInBytes = 1024 * 2048;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW);

Then for uploading the data into the buffer. Note that CreateVertexArray() fills the vector at the passed location with vertex data, with each vertex contributing 3 floats for position and 3 floats for normal (one of the most confusing things about the various tutorials was what format I should store and transfer my actual vertex data in; this seemed like a decent approximation):

std::vector<float>* VertArray = new std::vector<float>;
pWorld->CreateVertexArray(VertArray);
unsigned short Indice = 0;
for (int i = 0; i < VertArray->size(); ++i)
{
    std::cout << (*VertArray)[i] << std::endl;
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i]));
    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice));
    ++Indice;
}
delete VertArray;
Indice -= 1;

After that, in the game loop, I use this code:

    glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);        
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);    

    glEnableClientState(GL_VERTEX_ARRAY);         
    glVertexPointer(3, GL_FLOAT, 0, 0);
    glNormalPointer(GL_FLOAT, 0, 0);

    glDrawElements(GL_TRIANGLES, Indice, GL_UNSIGNED_SHORT, 0);

    glDisableClientState(GL_VERTEX_ARRAY);

    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

I'll be totally honest - I'm not sure I understand what the third parameter of glVertexPointer() and glNormalPointer() ought to be (stride is the offset in bytes, but Songho uses an offset of 0 bytes between values - what?), or what the last parameter of either of those is. The initial value is said to be 0; but it's supposed to be a pointer. Passing a null pointer in order to get the first coordinate/normal value of the array seems bizarre. This guy uses BUFFER_OFFSET(0) and BUFFER_OFFSET(12), but when I try that, I'm told that BUFFER_OFFSET() is undefined.

Plus, the last parameter of glDrawElements() is supposed to be an address, but again, Songho uses an address of 0. If I use &IndexBuffer instead of 0, I get a blank screen without anything rendering at all, except the background.

Can someone enlighten me, or at least point me in the direction of something that will help me figure this out? Thanks!

解决方案

The initial value is said to be 0; but it's supposed to be a pointer.

The context (not meaning the OpenGL one) matters. If one of the gl*Pointer functions is called with no Buffer Object being bound to GL_ARRAY_BUFFER, then it is a pointer into client process address space. If a Buffer Object is bound to GL_ARRAY_BUFFER it's an offset into the currently bound buffer object (you may thing the BO forming a virtual address space, to which the parameter to gl*Pointer is then an pointer into that server side address space).

Now let's have a look at your code

std::vector<float>* VertArray = new std::vector<float>;

You shouldn't really mix STL containers and new, learn about the RAII pattern.

pWorld->CreateVertexArray(VertArray);

This is problematic, since you'll delete VertexArray later on, leaving you with a dangling pointer. Not good.

unsigned short Indice = 0;
for (int i = 0; i < VertArray->size(); ++i)
{
    std::cout << (*VertArray)[i] << std::endl;
    glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i]));

You should submit large batches of data with glBufferSubData, not individual data points.

    glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice));

You're passing just incrementing indices into the GL_ELEMENT_ARRAY_BUFFER, thus enumerating the vertices. Why? You can have this, without the extra work using glDrawArrays insteaf of glDrawElements.

    ++Indice;
}
delete VertArray;

You're deleting VertArray, thus keeping a dangling pointer.

Indice -= 1;

Why didn't you just use the loop counter i?

So how to fix this? Like this:

std::vector<float> VertexArray;
pWorld->LoadVertexArray(VertexArray); // World::LoadVertexArray(std::vector<float> &);

glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*VertexArray->size(), &VertexArray[0] );

And using glDrawArrays; of course if you're not enumerating vertices, but have a list of faces→vertex indices, using a glDrawElements is mandatory.

这篇关于学习正确使用VBO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆