python opengl加速_OpenGL with python 渲染加速

在python的OpenGL环境下搭了一个简易的加载gltf动画的框架。测试的时候发现渲染很耗时,做了一些零碎的优化,现在的速度还算令人满意。印象比较深的一个优化是针对joint matrix的数据传输方式的改变,在此做个记录。

优化之前

之前因为骨骼关节数量超过了单个shader支持的uniform,所以把骨骼部分的数据改成了UBO(TODO:UBO相关博客)。

按理这一堆joint matrices和joint normal matrices是可以打包一块传上去,只传一次,这样效率会高很多。

如果用c++写,可以先开一块连续内存,然后每次更新这块内存,再一次打包传给ubo就行。但不知道python要怎么处理,所以一开始写成了这种扣扣搜搜的方式。

class Skin:

def __init__(self, skin: GLTFSkin):

...

def update_ubo(self):

glBindBuffer(GL_UNIFORM_BUFFER, self.ubo_id)

# 逐个更新joint matrix

for i, m in enumerate(self.joint_matrices):

glBufferSubData(GL_UNIFORM_BUFFER, i * glm.sizeof(glm.mat4), glm.sizeof(glm.mat4), glm.value_ptr(m))

offset = len(self.joint_matrices)

# 逐个更新joint normal matrix

for i, m in enumerate(self.joint_normal_matrices):

glBufferSubData(GL_UNIFORM_BUFFER, (i + offset) * glm.sizeof(glm.mat4), glm.sizeof(glm.mat4),

glm.value_ptr(m))

glBindBuffer(GL_UNIFORM_BUFFER, 0)

def update_joints(self, nodes, parent_node):

self.joint_matrices = []

self.joint_normal_matrices = []

# 重新计算joint matrix和joint normal matrix

# 添加到list里待更新

for i, node in enumerate(self.joints):

joint_matrix = parent_node.inverse_world_transform * \

node.world_transform * \

self.inverse_bind_matrices[i]

self.joint_matrices.append(joint_matrix)

normal_matrix = glm.transpose(glm.inverse(joint_matrix))

self.joint_normal_matrices.append(normal_matrix)

self.update_ubo()

优化之后

优化的思路很简单,就是提前开一块空间,每次更新里面的内容再整块打包上传。

class Skin:

def __init__(self, skin: GLTFSkin):

# 开一块连续的空间

self.mat_merge = np.empty((len(self.joints) * 2 * 4 * 4), dtype=np.float32)

# 获取这块连续空间的首地址

# A pointer to the memory area of ​​the array as a Python integer. 用于内存块的更新

# 这样的pointer能很方便的用+offset来索引相邻地址

self.mat_ctypes_ptr = self.mat_merge.ctypes.data

# LP_c_float object 用于ubo的更新

self.mat_ctypes_ptr_float = ctypes.cast(

self.mat_merge.ctypes.data,

ctypes.POINTER(ctypes.c_float))

self.glm_mat4x4_size = 16 * ctypes.sizeof(ctypes.c_float)

self.mat_offset = len(self.joints) * self.glm_mat4x4_size

def update_ubo(self):

glBindBuffer(GL_UNIFORM_BUFFER, self.ubo_id)

# 依旧使用glBufferSubData来传数据

# 但这次可以多个矩阵一块,只传一次

glBufferSubData(GL_UNIFORM_BUFFER, 0, 2 * self.mat_offset,

self.mat_ctypes_ptr_float)

glBindBuffer(GL_UNIFORM_BUFFER, 0)

def update_joints(self, nodes, parent_node):

a_ctypes_ptr = self.mat_ctypes_ptr

step = self.glm_mat4x4_size

offset = self.mat_offset

for i, node in enumerate(self.joints):

joint_matrix = (parent_node.inverse_world_transform *

node.world_transform *

self.inverse_bind_matrices[i])

# 使用cytpes.memmove来更新内存

ctypes.memmove(

a_ctypes_ptr + offset,

bytes(glm.transpose(glm.inverse(joint_matrix))),

ßstep)

ctypes.memmove(a_ctypes_ptr, bytes(joint_matrix), step)

a_ctypes_ptr += step

self.update_ubo()

ctypes.memmove(dst, src, count)

Same as the standard C memmove library function: copies count bytes from src to dst. dst and src must be integers or ctypes instances that can be converted to pointers.

也可以使用self.mat_ctypes_ptr_float作为ctypes.memmove函数的第一个参数,但无法像self.mat_ctypes_ptr那样,可以用+offset来方便地找到每个矩阵对应的地址。

原文链接:https://blog.csdn.net/suian0424/article/details/106524965

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值