我目前正在用C和C++为Blender制作一个渲染引擎.我想通过指针从C访问网格的顶点,以减少在Python中花费的时间,并避免不必要的数据重复.
我知道从ID
类派生的对象有一个as_pointer()
方法可用.但是,当我try 对网格的顶点集合使用as_pointer()
时,如下所示:
mesh = bpy.context.object.data
pointer = mesh.vertices.as_pointer()
我收到一个错误,指出bpy_prop_collection
对象没有属性as_pointer
,这是有道理的,因为bpy_prop_collection
不是从ID
派生的.
文档中提到,vertices
的类型是"MeshVerties bPY_PROP_COLLECTION of MeshVertex,(Readonly)"(doc),MeshVertices
应该是返回指针的ABE,但这既不是vertices
也不是it元素的类型.
作为一种解决办法,我一直将顶点数据检索到一个NumPy数组中,然后将该数组传递到我的C库中,如下面的示例代码所示:
import bpy
import numpy as np
import ctypes
obj = bpy.context.object # Suppose 'obj' is the mesh object
mesh = obj.data
# Allocate an array and copy the data, then set the pointer
# of the struct to the array
vert_array = np.zeros((len(mesh.vertices) * 3), dtype=np.float32)
mesh.vertices.foreach_get("co", vert_array)
vert_ptr = vert_array.ctypes.data_as(ctypes.POINTER(ctypes.c_float))
# Pass the pointer
lib = ctypes.CDLL("bin/libengine.so")
lib.load_vert.argtypes = [ctypes.POINTER(ctypes.float)]
lib.load_vert(vert_ptr)
但是,这种方法会复制内存中的顶点数据(一次在Blender的内部数据 struct 中,一次在NumPy数组中),并且需要进行可以避免的处理.
我研究了Blender的源代码,注意到底层的C/C++API确实允许直接内存访问.通过查看BKE_mesh_vert_positions
和CustomData_get_layer_named
函数,我们可以看到顶点存储在一个连续的数据块中:
BLI_INLINE const float (*BKE_mesh_vert_positions(const Mesh *mesh))[3]
{
return (const float(*)[3])CustomData_get_layer_named(&mesh->vdata, CD_PROP_FLOAT3, "position");
}
const void *CustomData_get_layer_named(const CustomData *data,
const eCustomDataType type,
const char *name)
{
int layer_index = CustomData_get_named_layer_index(data, type, name);
if (layer_index == -1) {
return nullptr;
}
return data->layers[layer_index].data;
}
这意味着,至少在理论上,我们可以有一个指向数据的指针.
在PythonAPI中有没有公开这些指针的方法,或者有没有一种方法可以从Python中使用C/C++API来直接获得内存,而不必编译Blender的定制版本?
任何关于如何直接访问这些指针或避免内存复制的替代解决方案的指导都将受到高度赞赏.