GLSL中的动态VBO读/写?
Posted
技术标签:
【中文标题】GLSL中的动态VBO读/写?【英文标题】:Dynamic VBO read/write in GLSL? 【发布时间】:2014-09-23 17:47:54 【问题描述】:现在在我看来似乎我的交错式 VBO 严格来说是“只读的”,但我想每帧都更新它(最好从 GLSL 更新)。
我有一个在轨道上移动的行星,下面的代码用于渲染轨道点。
问题大纲: 我希望该轨道上的每个点都有自己的“生命周期”,逻辑:
行星何时经过每个连续点?将生命周期更新为 1.0 并随着时间的推移而减少!这将用于创建每个移动物体的衰落轨道路径。现在我只是在寻找操纵 vbo 的方法......
如何在 GLSL 中读写 VBO?任何人都可以发布示例吗?
更新:我修改了上面的代码以使用转换反馈(由用户 Andon M. Coleman 建议),但我认为我可能做错了什么(我得到 glError):
设置:
// Initialize and upload to graphics card
glGenVertexArrays(1, &_vaoID);
glGenBuffers(1, &_vBufferID);
glGenBuffers(1, &_iBufferID);
glGenBuffers(1, &_tboID);
// First VAO setup
glBindVertexArray(_vaoID);
glBindBuffer(GL_ARRAY_BUFFER, _vBufferID);
glBufferData(GL_ARRAY_BUFFER, _vsize * sizeof(Vertex), _varray, GL_DYNAMIC_DRAW);
// TRANSFORM FEEDBACK
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, _tboID); // Specify buffer
// Allocate space without specifying data
glBufferData(GL_TRANSFORM_FEEDBACK_BUFFER,
_vsize*sizeof(Vertex), NULL, GL_DYNAMIC_COPY);
// Tell OGL which object to store the results of transform feedback
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _vBufferID); //correct?
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, location)));
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE,
sizeof(Vertex), reinterpret_cast<const GLvoid*>(offsetof(Vertex, velocity)));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _isize * sizeof(int), _iarray, GL_STREAM_DRAW);
渲染方法():
//disable fragment, so that we do a first run with feedback
glEnable(GL_RASTERIZER_DISCARD);
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _tboID);
glBeginTransformFeedback(_mode);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
glBindVertexArray(0);
glDisable(GL_RASTERIZER_DISCARD);
// then i attempt to do the actual draw
glBindVertexArray(_vaoID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _iBufferID);
glDrawElements(_mode, _isize, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
并且 - 在链接之前:
const GLchar* feedbackVaryings[] = "point_position" ;
glTransformFeedbackVaryings(_ephemerisProgram->getProgramID(), 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);
【问题讨论】:
我建议您阅读transform feedback。您无需在 GLSL 中执行任何特殊操作即可使用它。 @AndonM.Coleman - 我偶然发现了变换反馈以及:glMapBufferRange、glBufferSubData、双缓冲区和计算着色器,如下面的 user42813 建议的那样。很难知道哪一个给了我最大的灵活性(每个轨道的数学,即距离,点积计算等将是相同的,但我想稍后为每个线段的实例四边形添加一个几何着色器 - 拥有粗线。) 我很难确定哪种方法最好。我在某处读到添加了一个geom。着色器影响变换反馈的捕获(曾经有 1 个点,现在四边形的每个角有 4 个点)。 glBufferSubData 似乎没问题,但我找不到如何“重新上传”数据的示例,而且它似乎应该与 glMapBufferRange 结合使用?这仍然需要我在 CPU 上进行计算,然后上传到设备... 【参考方案1】:您不能从 Opengl 的渲染管道更改 VBO 的内容,但您可以根据时间使用技巧来更新它们,如果您使用的是 Opengl 4.4,您也可以使用 ComputeShaders,但它有点复杂在这里解释一下,hust google for it,祝你好运。
【讨论】:
【参考方案2】:如何在 GLSL 中读写 VBO?
你不能。 VBO 对普通渲染着色器严格来说是只读的。根本不可能进行修改(因为这会打开一个深不可测的蠕虫桶),但是使用转换反馈可以将着色器阶段的结果写入缓冲区。
或者您使用计算着色器。
问题大纲:我希望该轨道上的每个点都有自己的“生命周期”,逻辑:行星何时经过每个连续点?将生命周期更新为 1.0 并随着时间的推移而减少!
听起来像是计算着色器的任务。但老实说,我认为在 GPU 上处理 this 并没有什么好处。
【讨论】:
那么你建议在 CPU 上做更好,还是我使用转换反馈是正确的?如果您看到我修改了我的帖子以使用它,但我得到“无效操作”作为 glError - 我以前没有使用过这种技术。另一方面,如果它可以在 CPU 上做我想做的一切,那会让我的生活更轻松,但我不明白拥有 VBO 时这怎么可能? 我在上面发布的代码中所做的似乎是教科书。我认为问题可能是存在索引缓冲区?也许转换反馈在这种情况下不起作用......以上是关于GLSL中的动态VBO读/写?的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅如何抽取着色器代码到assets目录下的GLSL文件,以及如何通过Java或者C++代码来加载着GLSL文件?