glDrawArrays 之间的 glBufferSubData 调用 mangling data
glBufferSubData between glDrawArrays calls mangling data
似乎glBufferSubData
在我的glDrawArrays
调用之间覆盖或以某种方式篡改数据。 我正在使用Windows 7 64位,使用适用于我的Nvidia GeForce GT520M CUDA 1GB的最新驱动程序。
我有 2 个模型,每个模型都有一个动画。 模型有 1 个网格,该网格存储在同一个 VAO 中。 它们每个也有 1 个动画,用于渲染网格的骨骼转换存储在同一个 VBO 中。
我的工作流程如下所示:
- 计算模型的骨变换矩阵
- 使用
glBufferSubData
将骨转换矩阵加载到 OpenGL 中,然后绑定缓冲区 - 使用
glDrawArrays
渲染模型网格
对于一个模型,这是有效的(至少,大多数情况下 - 有时我在顶点之间会出现奇怪的间隙)。
但是,对于多个模型,骨骼转换矩阵数据似乎在对网格的渲染调用之间混淆了。
单模型动画窗口
两个模型动画窗口
我像这样加载我的骨骼转换数据:
void Animation::bind()
{
glBindBuffer(GL_UNIFORM_BUFFER, bufferId_);
glBufferSubData(GL_UNIFORM_BUFFER, 0, currentTransforms_.size() * sizeof(glm::mat4), ¤tTransforms_[0]);
bindPoint_ = openGlDevice_->bindBuffer( bufferId_ );
}
我像这样渲染我的网格:
void Mesh::render()
{
glBindVertexArray(vaoId_);
glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
glBindVertexArray(0);
}
如果我在调用render()
之后添加对glFinish()
的调用,它工作得很好! 这似乎向我表明,由于某种原因,一个动画的转换矩阵数据正在"流血"到下一个动画。
怎么会这样? 我的印象是,如果我在使用缓冲区时调用glBufferSubData
(例如用于glDrawArrays
),那么它会阻塞。 难道不是这样吗?
值得一提的是,同样的代码在 Linux 中运行良好。
注意:与我删除的上一篇文章有关。
网格加载代码:
void Mesh::load()
{
LOG_DEBUG( "loading mesh '" + name_ +"' into video memory." );
// create our vao
glGenVertexArrays(1, &vaoId_);
glBindVertexArray(vaoId_);
// create our vbos
glGenBuffers(5, &vboIds_[0]);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[0]);
glBufferData(GL_ARRAY_BUFFER, vertices_.size() * sizeof(glm::vec3), &vertices_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[1]);
glBufferData(GL_ARRAY_BUFFER, textureCoordinates_.size() * sizeof(glm::vec2), &textureCoordinates_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[2]);
glBufferData(GL_ARRAY_BUFFER, normals_.size() * sizeof(glm::vec3), &normals_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[3]);
glBufferData(GL_ARRAY_BUFFER, colors_.size() * sizeof(glm::vec4), &colors_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, 0, 0);
if (bones_.size() == 0)
{
bones_.resize( vertices_.size() );
for (auto& b : bones_)
{
b.weights = glm::vec4(0.25f);
}
}
glBindBuffer(GL_ARRAY_BUFFER, vboIds_[4]);
glBufferData(GL_ARRAY_BUFFER, bones_.size() * sizeof(VertexBoneData), &bones_[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(4);
glVertexAttribIPointer(4, 4, GL_INT, sizeof(VertexBoneData), (const GLvoid*)0);
glEnableVertexAttribArray(5);
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, sizeof(VertexBoneData), (const GLvoid*)(sizeof(glm::ivec4)));
glBindVertexArray(0);
}
动画 UBO 设置:
void Animation::setupAnimationUbo()
{
bufferId_ = openGlDevice_->createBufferObject(GL_UNIFORM_BUFFER, Constants::MAX_NUMBER_OF_BONES_PER_MESH * sizeof(glm::mat4), ¤tTransforms_[0]);
}
其中Constants::MAX_NUMBER_OF_BONES_PER_MESH
设置为 100。
在OpenGlDevice
:
GLuint OpenGlDevice::createBufferObject(GLenum target, glmd::uint32 totalSize, const void* dataPointer)
{
GLuint bufferId = 0;
glGenBuffers(1, &bufferId);
glBindBuffer(target, bufferId);
glBufferData(target, totalSize, dataPointer, GL_DYNAMIC_DRAW);
glBindBuffer(target, 0);
bufferIds_.push_back(bufferId);
return bufferId;
}
对于这种情况,这些用法标志大多是正确的,尽管您可以考虑尝试GL_STREAM_DRAW
。
由于某种原因,驱动程序似乎无法隐式同步,因此你可能想要尝试一种技术,以便首先消除同步的需要。我建议缓冲区孤立:在发送数据之前使用 NULL 调用 glBufferData (...)
以获取数据指针。这将允许当前使用 UBO 的命令继续使用原始数据存储,而无需强制同步,因为您将在发送新数据之前分配新的数据存储。前面提到的命令完成后,原始数据存储将被孤立,GL 实现将释放它。
在较新的 OpenGL 实现中,可以使用glInvalidateBuffer[Sub]Data (...)
来提示驱动程序执行上面讨论的操作。同样,您可以将glMapBufferRange (...)
与适当的标志一起使用,以更明确地控制所有这些行为。取消映射将隐式刷新和同步对缓冲区对象的访问,除非另有说明,如果你不想弄乱无同步缓冲区更新逻辑,这可能会让你的驱动程序完成其工作。
我提到的大部分内容在这里都有更详细的讨论。
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 'string.assign(string.data(), 5)' 是明确定义的还是 UB?
- 收到错误"invalid use of non-static data member 'stu::n' "
- C++ 初始化 .data 部分中的变量
- 模式"allocate memory or use existing data"
- boost::asio data owning `ConstBufferSequence`
- Python to C++ Data structure API
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- protobuf C++ SQLite handle blob data
- 错误:字段'dateOfBirth'的类型不完整'Poco::Data::Date'
- 为什么构造函数 Message(const T&data) 与 Message(T&& data) 冲突,当 T = int&时?
- "thread-safe data"与"thread-safe code/functions"的区别
- 如何找到目标文件 *.o 的 ram rom 使用情况(.bss .text .rodata .data)?
- 这在C++ "It does not own the underlying data, and so is cheap to copy or assign"中意味着什么
- 使用 .data() 将字符数组转换为 std::string 不会转换整个数组
- *(int*)&data[18]在这段代码中实际上做了什么?
- 出现这种错误的原因是什么"invalid use of non-static data member "
- 构造中错误:未在此范围中声明"data"
- 我可以在初始化之前使用 std::array 成员变量中的 data() 指针吗?发出警告
- glDrawArrays 之间的 glBufferSubData 调用 mangling data