pyopengl - 动态更新顶点缓冲区对象中的值

2023-12-21

我想创建具有可拖动顶点的多边形PyOpenGL。经过一番阅读后,VBO 似乎是实现这一目标的明智方法。

以前从未使用过 VBO,我很难弄清楚如何动态更新它们 - 理想情况下,我只想修改 a 的元素numpy顶点数组,然后仅将更改的元素传播到 GPU。我原以为OpenGL.arrays.vbo.VBO包装器自动执行此操作copy_data()方法,不过好像不行。

这是一个愚蠢的例子:

from OpenGL import GL as gl
from OpenGL import GLUT as glut
from OpenGL.arrays import vbo
import numpy as np

class VBOJiggle(object):

    def __init__(self,nvert=100,jiggliness=0.01):
        self.nvert = nvert
        self.jiggliness = jiggliness

        verts = 2*np.random.rand(nvert,2) - 1
        self.verts = np.require(verts,np.float32,'F')
        self.vbo = vbo.VBO(self.verts)

    def draw(self):

        gl.glClearColor(0,0,0,0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)

        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)

        self.vbo.bind()

        gl.glVertexPointer(2,gl.GL_FLOAT,0,self.vbo)
        gl.glColor(0,1,0,1)
        gl.glDrawArrays(gl.GL_LINE_LOOP,0,self.vbo.data.shape[0])

        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)

        self.vbo.unbind()

        self.jiggle()

        glut.glutSwapBuffers()

    def jiggle(self):

        # jiggle half of the vertices around randomly
        delta = (np.random.rand(self.nvert//2,2) - 0.5)*self.jiggliness
        self.verts[:self.nvert:2] += delta

        # the data attribute of the vbo is the same as the numpy array
        # of vertices
        assert self.verts is self.vbo.data

        # # Approach 1:
        # # it seems like this ought to work, but it doesn't - all the
        # # vertices remain static even though the vbo's data gets updated
        # self.vbo.copy_data()

        # Approach 2:
        # this works, but it seems unnecessary to copy the whole array
        # up to the GPU, particularly if the array is large and I have
        # modified only a small subset of vertices
        self.vbo.set_array(self.verts)

if __name__ == '__main__':
    glut.glutInit()
    glut.glutInitDisplayMode( glut.GLUT_DOUBLE | glut.GLUT_RGB )
    glut.glutInitWindowSize( 250, 250 )
    glut.glutInitWindowPosition( 100, 100 )
    glut.glutCreateWindow( None )

    demo = VBOJiggle()
    glut.glutDisplayFunc( demo.draw )
    glut.glutIdleFunc( demo.draw )

    glut.glutMainLoop()

要完整回答这个问题,就不得不先提一下OpenGL缓冲区更新。

OpenGL指令glBufferData https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferData.xhtml创建并初始化缓冲区对象的数据存储。缓冲区对象的现有数据存储被完全销毁,并创建新的数据存储(可能具有不同的大小)。如果将数据指针传递给函数,则数据存储将完全由数据初始化。假设缓冲区的大小和提供的数据的大小相等。

glBufferSubData https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glBufferSubData.xhtml更新现有数据存储的整个数据或数据子集。假设数据存储是之前创建的glBufferData。不会销毁或创建任何数据存储。

当然,从技术上来说glBufferData总是可以用来代替glBufferSubData, but glBufferSubData会表现得更好,因为消除了昂贵的缓冲区创建(分配)。

Using

self.vbo.set_array(self.verts)

是一个坏主意,因为从实现中可以看出(PyOpenGL/OpenGL/arrays/vbo.py https://github.com/Distrotech/PyOpenGL/blob/master/OpenGL/arrays/vbo.py),此方法创建一个全新的缓冲区,可能具有新的大小,并将强制重新创建缓冲区对象的数据存储(因为self.copied = False).

如果之前创建了缓冲区,那么self.vbo.copy_data()将通过以下方式更新数据glBufferSubData (see if self.copied: in copy_data)。为了使这项工作有效,缓冲区必须是当前绑定的缓冲区(self.vbo.bind())。此外还必须设置复制信息(VBO.copy_segments)。复制信息由项目设置者声明(VBO.__setitem__).

这意味着,在“方法 1”中,您必须执行如下操作:

self.vbo[:] = self.verts
self.vbo.bind()
self.vbo.copy_data()

Since OpenGL.arrays.vbo http://pyopengl.sourceforge.net/documentation/pydoc/OpenGL.arrays.vbo.html无非是 OpenGL 缓冲区指令的包装器,我更喜欢使用glBufferSubData直接,在这种情况下效果最好:

# Approach 3:
# Direct buffer update by `glBufferSubData`
self.vbo.bind()
self.vbo.implementation.glBufferSubData(self.vbo.target, 0, self.vbo.data)

通过这种方法,甚至可以更新数据存储的子集。注意第二个参数glBufferSubData是缓冲区对象数据存储的字节偏移量。此外还有一个重载实现,它可以处理缓冲区大小和直接数据指针。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pyopengl - 动态更新顶点缓冲区对象中的值 的相关文章

随机推荐

  • cv::Mat 到 QImage 转换

    我发现了非常相似的主题 如何将 opencv cv Mat 转换为 qimage https stackoverflow com questions 5026965 how to convert an opencv cvmat to qim
  • bash脚本循环多个变量

    我正在尝试写类似以下内容 for i in a z j in 1 26 do echo dev sd i 1 disk j ext4 noatime 1 1 gt gt test done 当然 这不是正确的语法 有人可以帮助我使用正确的语
  • 在运行时从 iOS 上的本机方法创建委托

    这是一个MonoTouch 专用问题 我目前正在开发一个 OpenGL 的包装器 它与 OpenTK 等包装器有很大不同 该包装器用于实现更快的 OpenGL 开发 方法不是这样声明的 void glGenTextures Int32 n
  • 创建一个php函数来返回mysql结果

    我试图创建一个函数 它将返回一个 mysql 查询 然后我可以循环遍历并处理结果 但它似乎不起作用 我什至可能没有以正确的方式这样做 function GetAccounts username require dbconn php resu
  • 无法在 Kafka 中使用来自远程计算机的消息

    我在我的一台机器上创建了一个kafka主题 其IP为192 168 25 50 主题名称为test poc 然后通过使用 kafka console Producer 我生成了如下消息 kafka console producer brok
  • 装有 iOS 6 AVAudioPlayer 的 iPhone 4S 可以工作,但没有声音

    我创建了一个简单的音频应用程序来播放 mp3 文件 它在模拟器 iOS 5 和 6 和 iPod3GS iOS 5 1 上运行没有问题 但是当我在 iPhone4S iOS 6 上尝试时 它似乎可以工作 但没有任何声音 audioPlaye
  • Pharo 有 CAS 吗?

    在学习Python时 我发现了SymPy模块 它实际上是一个完整的计算机代数系统 CAS 你可以用它来解决数学中的符号问题 比如微分方程 多项式等等 现在我正在学习 Pharo 我想知道是否有一种方法可以在 Pharo 中进行符号数学运算
  • ctrl+space 键绑定不适用于 Sublime Text 3 中的注释

    安装 Sublime Text 3 Build 3059 后 我尝试像过去一样配置一些按键绑定 所以我在 首选项 按键绑定 用户 中配置了这个 keys ctrl space command toggle comment args bloc
  • 在 SwiftUI 中绘制动画路径描边

    要为过去的路径设置动画 我可以这样做 let pathLayer CAShapeLayer let pathAnimation CABasicAnimation keyPath strokeEnd pathLayer path path c
  • 获取输入框中选定的文本

    是否可以使用 jQuery 或 vanilla JavaScript 获取网站输入框中选定的文本 我尝试过var selectedText window getSelection toString 但这段代码只能获取 a 中的文本段落并且不
  • 检查今天的日期是否在其他两个日期之间[重复]

    这个问题在这里已经有答案了 我想检查今天的日期是否在一个时期的开始日期和结束日期之间 冬天 夏天 春天等 如果今天的日期介于冬季期间 它会将 season 变量设置为哪个时期 但目前它只给我 01 01 我不明白为什么 感谢帮助 seaso
  • 如何使用 requirejs 分解部分淘汰视图模型

    我目前正在开发一个应用程序 由于功能太多 该应用程序正在不断扩展 这里我将提供一些示例代码以供理解 function test var self this Define Properties self TaskSection ko obse
  • iOS 12 不支持部分 PWA 的离线功能

    iOS 12 Safari 不支持某些 PWA 渐进式 Web 应用程序 的离线功能 Safari 似乎没有正确缓存这些网络应用程序中的资源 例如 以下 PWA 无法在 iOS 12 和 12 1 中离线工作 但它们在 Android 或
  • 输入字段的大小可以设置为百分比值吗?

    我无法创建一个居中且覆盖浏览器窗口宽度 80 的输入字段
  • 使用 scipy.misc.imread 时出错:AttributeError: __float__

    我正在使用 scipy misc imread 将 png 文件转换为浮点数数组 scipy misc imread rawImagePath astype scipy float 其中 rawImagePath 是文件的完整路径 这在绝大
  • C++ 库渲染 ODF 文档?

    我无法找到任何开源库来使用 C 渲染 ODF 文档 我发现 ODKit 支持 Java 和 AODL for NET C 有谁有任何想法或为我提供任何指示 我找到了一个Qt源来解析PDF http qt apps org content s
  • 获取 SoapBody 元素值

    这是我从服务器得到的响应 虽然我可以接受MM7Version元素值 我无法获取Status元素值 它返回 null SoapMeesage XML 响应
  • 服务 Firestore 不可用

    我正在尝试使用纯 JavaScript 连接到我的 firestore 我现在想加快速度并跑步 索引 js import app from firebase js import getFirestore from https www gst
  • RS485:设备的 ioctl 不合适

    我使用以下代码访问 RS485 从站 但收到错误 读取 ioctl 端口 25 时出错 设备的 ioctl 不合适 我的代码如下 include
  • pyopengl - 动态更新顶点缓冲区对象中的值

    我想创建具有可拖动顶点的多边形PyOpenGL 经过一番阅读后 VBO 似乎是实现这一目标的明智方法 以前从未使用过 VBO 我很难弄清楚如何动态更新它们 理想情况下 我只想修改 a 的元素numpy顶点数组 然后仅将更改的元素传播到 GP