直接从 numpy 数据创建搅拌机网格?
Creating a blender mesh directly from numpy data?
是否可以直接从高效的 numpy 数组创建 Blender 网格而不需要通过(缓慢且 space 浪费)POD python 数据类型?这是一个说明我的意思的脚本。我需要对我的 numpy 数据调用 .tolist()
才能使脚本正常工作。有没有其他更高效的API?
# Create a mesh from numpy arrays. Can you do this without tolist()?
import bpy
import numpy as np
verts = np.array([
(1, 1, 1),
(-1, 1, -1),
(-1, -1, 1),
(1, -1, -1),
], dtype=np.float32)
faces = np.array([[0, 1, 2], [0, 2, 3], [0, 3, 1], [2, 1, 3]],
dtype=int)
mesh = bpy.data.meshes.new('TetraMesh')
obj = bpy.data.objects.new('Tetra', mesh)
# Must call tolist() to pass to from_pydata()!
mesh.from_pydata(verts.tolist(),[],faces.tolist())
mesh.update(calc_edges=True) # Update mesh with new data
bpy.context.collection.objects.link(obj) # Link to scene
这个对我有用foreach_set。
您不必将 numpy 数组转换为列表。
每一行我都注释了,应该很清楚它是如何工作的。
import bpy
import numpy
# the numpy array must be in this form
vertices = numpy.array([
1, 1, 1, # vertex 0
-1, 1, -1, # vertex 1
-1, -1, 1, # vertex 2
1, -1, -1 # vertex 3
], dtype=numpy.float32)
# vertices for each polygon
vertex_index = numpy.array([
0, 1, 2, # first polygon starting at 0
0, 2, 3, # second polygon starting at 3
0, 3, 1, # third polygon starting at 6
2, 1, 3 # forth polygon starting at 9
], dtype=numpy.int32)
# every polygon start at a specific index in vertex_index array
loop_start = numpy.array([
0, # polygon start at 0 --> 0, 1, 2
3, # polygon start at 3 --> 0, 2, 3
6, # polygon start at 6 --> 0, 3, 1
9 # polygon start at 9 --> 2, 1, 3
], dtype=numpy.int32)
# lenght of the loop
num_loops = loop_start.shape[0]
# Length of each polygon in number of vertices
loop_total = numpy.array([3,3,3,3], dtype=numpy.int32)
# Create mesh object based on the arrays above
mesh = bpy.data.meshes.new(name='created mesh')
# Number of vertices in vertices array (12 // 3)
num_vertices = vertices.shape[0] // 3
# add the amount of vertices, in this case 4.
mesh.vertices.add(num_vertices)
# use the vertices numpy array
mesh.vertices.foreach_set("co", vertices)
# total indexes in vertex_index
num_vertex_indices = vertex_index.shape[0]
# add the amount of the vertex_index array, in this case 12
mesh.loops.add(num_vertex_indices)
# set the vertx_index
mesh.loops.foreach_set("vertex_index", vertex_index)
# add the length of loop_start array
mesh.polygons.add(num_loops)
# generate the polygons
mesh.polygons.foreach_set("loop_start", loop_start)
mesh.polygons.foreach_set("loop_total", loop_total)
# validate your mesh
mesh.update()
mesh.validate()
# create the object with the mesh just created
obj = bpy.data.objects.new('created object', mesh)
# add the Oject to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj)
如果你想了解更多还有另一个更一致的例子here
Blender 最近在 master 分支中修复了这个问题
https://developer.blender.org/rBacf1374495c19d7b600ad12f12a01d6e8dfe7900
当前的解决方法是使用覆盖 __bool__
方法的 class 查看数组,这样当 Blender 检查数组的 bool 值时,它实际上做了 Blender 开发人员打算做的事情(检查数组长度是否 > 0)
class ndarray_pydata(np.ndarray):
def __bool__(self) -> bool:
return len(self) > 0
edges = edges_np.view(ndarray_pydata)
faces = faces_np.view(ndarray_pydata)
mesh.from_pydata(vertices, edges, faces)
完整的工作示例:
https://gist.github.com/iyadahmed/7c7c0fae03c40bd87e75dc7059e35377
是否可以直接从高效的 numpy 数组创建 Blender 网格而不需要通过(缓慢且 space 浪费)POD python 数据类型?这是一个说明我的意思的脚本。我需要对我的 numpy 数据调用 .tolist()
才能使脚本正常工作。有没有其他更高效的API?
# Create a mesh from numpy arrays. Can you do this without tolist()?
import bpy
import numpy as np
verts = np.array([
(1, 1, 1),
(-1, 1, -1),
(-1, -1, 1),
(1, -1, -1),
], dtype=np.float32)
faces = np.array([[0, 1, 2], [0, 2, 3], [0, 3, 1], [2, 1, 3]],
dtype=int)
mesh = bpy.data.meshes.new('TetraMesh')
obj = bpy.data.objects.new('Tetra', mesh)
# Must call tolist() to pass to from_pydata()!
mesh.from_pydata(verts.tolist(),[],faces.tolist())
mesh.update(calc_edges=True) # Update mesh with new data
bpy.context.collection.objects.link(obj) # Link to scene
这个对我有用foreach_set。 您不必将 numpy 数组转换为列表。 每一行我都注释了,应该很清楚它是如何工作的。
import bpy
import numpy
# the numpy array must be in this form
vertices = numpy.array([
1, 1, 1, # vertex 0
-1, 1, -1, # vertex 1
-1, -1, 1, # vertex 2
1, -1, -1 # vertex 3
], dtype=numpy.float32)
# vertices for each polygon
vertex_index = numpy.array([
0, 1, 2, # first polygon starting at 0
0, 2, 3, # second polygon starting at 3
0, 3, 1, # third polygon starting at 6
2, 1, 3 # forth polygon starting at 9
], dtype=numpy.int32)
# every polygon start at a specific index in vertex_index array
loop_start = numpy.array([
0, # polygon start at 0 --> 0, 1, 2
3, # polygon start at 3 --> 0, 2, 3
6, # polygon start at 6 --> 0, 3, 1
9 # polygon start at 9 --> 2, 1, 3
], dtype=numpy.int32)
# lenght of the loop
num_loops = loop_start.shape[0]
# Length of each polygon in number of vertices
loop_total = numpy.array([3,3,3,3], dtype=numpy.int32)
# Create mesh object based on the arrays above
mesh = bpy.data.meshes.new(name='created mesh')
# Number of vertices in vertices array (12 // 3)
num_vertices = vertices.shape[0] // 3
# add the amount of vertices, in this case 4.
mesh.vertices.add(num_vertices)
# use the vertices numpy array
mesh.vertices.foreach_set("co", vertices)
# total indexes in vertex_index
num_vertex_indices = vertex_index.shape[0]
# add the amount of the vertex_index array, in this case 12
mesh.loops.add(num_vertex_indices)
# set the vertx_index
mesh.loops.foreach_set("vertex_index", vertex_index)
# add the length of loop_start array
mesh.polygons.add(num_loops)
# generate the polygons
mesh.polygons.foreach_set("loop_start", loop_start)
mesh.polygons.foreach_set("loop_total", loop_total)
# validate your mesh
mesh.update()
mesh.validate()
# create the object with the mesh just created
obj = bpy.data.objects.new('created object', mesh)
# add the Oject to the scene
scene = bpy.context.scene
scene.collection.objects.link(obj)
如果你想了解更多还有另一个更一致的例子here
Blender 最近在 master 分支中修复了这个问题 https://developer.blender.org/rBacf1374495c19d7b600ad12f12a01d6e8dfe7900
当前的解决方法是使用覆盖 __bool__
方法的 class 查看数组,这样当 Blender 检查数组的 bool 值时,它实际上做了 Blender 开发人员打算做的事情(检查数组长度是否 > 0)
class ndarray_pydata(np.ndarray):
def __bool__(self) -> bool:
return len(self) > 0
edges = edges_np.view(ndarray_pydata)
faces = faces_np.view(ndarray_pydata)
mesh.from_pydata(vertices, edges, faces)
完整的工作示例: https://gist.github.com/iyadahmed/7c7c0fae03c40bd87e75dc7059e35377