我正在开发一个模拟降雨的C ++程序。 我正在使用OpenGL实例功能来渲染越来越多的水滴。 (一个实例=一个液滴)
程序在调用glDrawElementsInstances
时运行正常,直到实例数达到18680.然后,它冻结或产生奇怪的行为(巨大的减速,实例的不连贯渲染)。
我的渲染循环:
GLObject GLDrop(*this->_model._drop, *this->_shader); // generate buffer
while (!glfwWindowShouldClose(this->_window))
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
this->_model._drop->create();
GLDrop.setDropState();
glDrawElementsInstanced(GL_TRIANGLE_STRIP, this->_model._drop->getElementsSize(), GL_UNSIGNED_INT, 0, this->_model._drop->getInstances());
GLDrop.disableDropState();
glfwSwapBuffers(this->_window);
glfwPollEvents();
}
我的缓冲区生成函数,在渲染循环之前调用:
void GLObject::generateDropBuffers(void)
{
glGenBuffers(1, &this->_vbo);
glBindBuffer(GL_ARRAY_BUFFER, this->_vbo);
glBufferData(GL_ARRAY_BUFFER, this->_module.getVerticesSize() * sizeof(GLfloat), this->_module.getVertices(), GL_STATIC_DRAW);
glGenBuffers(1, &this->_ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->_ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->_module.getElementsSize() * sizeof(GLuint), this->_module.getElements(), GL_STATIC_DRAW);
glGenBuffers(1, &this->_pbo);
glBindBuffer(GL_ARRAY_BUFFER, this->_pbo);
glBufferData(GL_ARRAY_BUFFER, this->_module.getMaxInstances() * DIMENSIONS * sizeof(GLfloat), NULL, GL_DYNAMIC_DRAW);
glGenBuffers(1, &this->_cbo);
glBindBuffer(GL_ARRAY_BUFFER, this->_cbo);
glBufferData(GL_ARRAY_BUFFER, this->_module.getMaxInstances() * COLOR_CHANNELS * sizeof(GLfloat), NULL, GL_DYNAMIC_DRAW);
}
每次调用Drop.create()时,都会创建一批新的Droplet,增加要绘制到屏幕的实例数。
void Drop::create(void)
{
unsigned int i;
unsigned int j;
if (this->_instances < this->_maxInstances - this->_dropBatch)
{
for (GLuint drop = 0; drop < this->_dropBatch; ++drop)
{
i = this->_instances * DIMENSIONS;
j = this->_instances * COLOR_CHANNELS;
this->_positions[i] = rand() % this->_model._vertexCol * UNIT;
this->_positions[i + 1] = this->_model._top + 3.0f * UNIT;
this->_positions[i + 2] = rand() % this->_model._vertexRow * UNIT;
this->_colors[j] = 0.0f;
this->_colors[j + 1] = 0.0f;
this->_colors[j + 2] = 1.0f;
this->_colors[j + 3] = 1.0f;
this->_instances += 1;
}
}
}
我的缓冲区绑定功能:
void GLObject::setDropState(void)
{
GLuint instances = this->_module.getInstances() - this->_module.getBatchSize();
GLuint posOffset = instances * DIMENSIONS;
GLuint colorOffset = instances * COLOR_CHANNELS;
GLuint posSize = this->_module.getBatchSize() * DIMENSIONS * sizeof(GLfloat);
GLuint colorSize = this->_module.getBatchSize() * COLOR_CHANNELS * sizeof(GLfloat);
glBindBuffer(GL_ARRAY_BUFFER, this->_vbo);
glVertexAttribPointer(this->_shader.getAPosition(), DIMENSIONS, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(this->_shader.getAPosition());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->_ebo);
glBindBuffer(GL_ARRAY_BUFFER, this->_pbo);
glBufferSubData(GL_ARRAY_BUFFER, posOffset * sizeof(GLfloat), posSize, this->_module.getPositions() + posOffset);
glVertexAttribPointer(this->_shader.getAInstance(), DIMENSIONS, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(this->_shader.getAInstance());
glBindBuffer(GL_ARRAY_BUFFER, this->_cbo);
glBufferSubData(GL_ARRAY_BUFFER, colorOffset * sizeof(GLfloat), colorSize, this->_module.getColors() + colorOffset);
glVertexAttribPointer(this->_shader.getAColors(), COLOR_CHANNELS, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(this->_shader.getAColors());
glVertexAttribDivisor(this->_shader.getAPosition(), 0);
glVertexAttribDivisor(this->_shader.getAInstance(), 1);
glVertexAttribDivisor(this->_shader.getAColors(), 1);
}
经过测试:
NVIDIA GeForce GT 330M 512 MB,MacbookPro。
NVIDIA GeForce 9400M 256 MB,MacbookPro
我不知道可能是什么问题。我可以在一次通话中绘制的实例数量有限制吗? (我非常怀疑是这种情况)。 我使用的缓冲区比我需要的大,以确保它不是内存访问问题。
这可能是内存对齐问题吗?
OpenGL手册说这是关于对齐的,但我无法真正理解。
客户必须使数据元素符合要求 客户端平台,具有额外的基本级要求 缓冲区内的偏移量包含N个字节的数据 Ñ
欢迎任何帮助。
我的场景,在撞击之前绘制了18860个液滴实例
修改
在Google上搜索时,我在此处发现了类似的案例:https://www.opengl.org/discussion_boards/showthread.php/181142-glDrawArraysInstanced-max-number-of-instances
线程的作者和我有同样的问题,但实际上是实例数量的两倍(我猜因为他的GPU内存是512而不是256)。此外,我发现根据每个循环添加的实例数量,我有不同的行为。
例如: 如果我为每个循环添加100个实例,我的程序就会冻结。 如果我为每个循环添加200个或更多实例,我的程序会减慢到4fps。
在我上面发布的链接的底部,authour exaplains详细说明了这种行为的原因。显然,差异是由于跳过(或不跳跃)特定的实例间隔。 如果我为每个循环添加100个实例,我会陷入死亡间隙(如此冻结),但是如果我添加超过100个,我会跳过死亡间隙(如此巨大的减速)
对这个奇怪的macbook&#34; bug&#34;?
的任何想法答案 0 :(得分:0)
我在glDrawElementsInstancedEXT(iPhone 5)上遇到了类似的问题。我尝试了不同的网格,发现如果索引总数(实例数乘以网格索引数)超过大约4百万,则FPS下降百倍。我想补充一点,使用glDrawElements的绘图在这种情况下以类似的方式减慢。
还有另一个问题。 如果多个实例超过65535,glDrawElementsInstancedEXT将根据第一次调用glDrawElementsInstancedEXT中绘制的实例数绘制:
如果第一次调用中的实例数小于65536,则以下调用仅绘制前65535个实例
如果第一次调用中的实例数超过65535,则以下调用将绘制完整的实例数。
它看起来像是驱动程序中的错误。