Nous allons résumer comment accéder aux données de maillage avec Blender Python. Ce n'est pas si difficile de chercher, mais je n'ai pas beaucoup d'informations, je vais donc les rassembler pour qu'elles puissent être répertoriées comme aide-mémoire. Il n'y a aucune garantie que les méthodes décrites ici soient optimales en termes de vitesse. S'il vous plaît laissez-moi savoir s'il existe une autre meilleure façon.
Ci-dessous, je voudrais résumer l'exemple de code qui crée des cubes et les définit avec UV, Vertex Color, Shape key et Skin Weight (Vertex Group). Il contient également le code et le journal pour imprimer l'ensemble de données qu'ils contiennent.
Postscript (03/04/2019): La version de Blender est devenue 2.80 et l'API a été partiellement modifiée et a cessé de fonctionner, alors je l'ai corrigée. Fondamentalement, les 4 points suivants.
Vous pouvez également créer un maillage en entrant en mode édition et en le créant en tant que BMesh, mais voici comment le créer en mode objet.
create_mesh.py
import bpy
verts = [[-1.0, -1.0, 1.0], [1.0, -1.0, 1.0], [1.0, 1.0, 1.0], [-1.0, 1.0, 1.0],
[-1.0, -1.0, -1.0], [1.0, -1.0, -1.0], [1.0, 1.0, -1.0], [-1.0, 1.0, -1.0], ]
faces = [[0,1,2,3], [0,4,5,1], [1,5,6,2], [2,6,7,3], [0,3,7,4], [4,7,6,5]]
msh = bpy.data.meshes.new(name="cubemesh")
#msh = bpy.data.meshes.new("cubemesh")
msh.from_pydata(verts, [], faces)
msh.update()
obj = bpy.data.objects.new(name="cube", object_data=msh)
#obj = bpy.data.objects.new("cube", msh)
scene = bpy.context.scene
#scene.objects.link(obj)
scene.collection.objects.link(obj)
En tant que flux,
meshes.new
from_pydata
msh.update ()
. Cela peut ne pas être nécessaire si vous appelez from_pydata.scene.objects.link
à la scène.La partie [] de l'argument central de from_pydata
définit les informations de bord. Sinon, il sera calculé automatiquement à partir des informations Face, donc si vous souhaitez créer un maillage qui génère des faces, il n'y a pas de problème avec un tableau vide. Blender peut également créer un maillage sans faces, auquel cas vous pouvez spécifier l'arête et laisser la spécification Face Index vide. Vous pouvez créer un maillage sans faces avec un script, tel qu'un maillage pour un contrôleur de rig.
--vertices propriété --index: Index des sommets --co: Coordonnées des sommets --normal: sommet normal
#Énumération des informations sur les sommets
print("num of vertices:", len(msh.vertices))
for vt in msh.vertices:
print("vertex index:{0:2} co:{1} normal:{2}".format(vt.index, vt.co, vt.normal))
production
num of vertices: 8
vertex index: 0 co:<Vector (-1.0000, -1.0000, 1.0000)> normal:<Vector (-0.5773, -0.5773, 0.5773)>
vertex index: 1 co:<Vector (1.0000, -1.0000, 1.0000)> normal:<Vector (0.5773, -0.5773, 0.5773)>
vertex index: 2 co:<Vector (1.0000, 1.0000, 1.0000)> normal:<Vector (0.5773, 0.5773, 0.5773)>
vertex index: 3 co:<Vector (-1.0000, 1.0000, 1.0000)> normal:<Vector (-0.5773, 0.5773, 0.5773)>
vertex index: 4 co:<Vector (-1.0000, -1.0000, -1.0000)> normal:<Vector (-0.5773, -0.5773, -0.5773)>
vertex index: 5 co:<Vector (1.0000, -1.0000, -1.0000)> normal:<Vector (0.5773, -0.5773, -0.5773)>
vertex index: 6 co:<Vector (1.0000, 1.0000, -1.0000)> normal:<Vector (0.5773, 0.5773, -0.5773)>
vertex index: 7 co:<Vector (-1.0000, 1.0000, -1.0000)> normal:<Vector (-0.5773, 0.5773, -0.5773)>
print("num of edges:", len(msh.edges))
for ed in msh.edges:
print("edge index:{0: 2} v0:{0} v1:{1}".format(ed.index, ed.vertices[0], ed.vertices[1]))
production
num of edges: 12
edge index: 0 v0: 4 v1: 5
edge index: 1 v0: 3 v1: 7
edge index: 2 v0: 6 v1: 7
edge index: 3 v0: 2 v1: 6
edge index: 4 v0: 5 v1: 6
edge index: 5 v0: 0 v1: 1
edge index: 6 v0: 4 v1: 7
edge index: 7 v0: 1 v1: 2
edge index: 8 v0: 1 v1: 5
edge index: 9 v0: 2 v1: 3
edge index:10 v0: 0 v1: 3
edge index:11 v0: 0 v1: 4
La propriété ** polygones **, pas les faces. Il y a plus de logiciels avec les faces de nom de propriété, et j'essaye juste d'y accéder avec des visages? Je le souligne parce que ça devient.
--polygons, propriété --index: Index du polygone --vertices: Index des sommets adjacents --loop_start: Index des données de boucle de début pour itérer les arêtes et les sommets de ce polygone (le maillage a une propriété de boucles et un index dessus) --loop_total: nombre de boucles, réel, nombre de sommets de polygone --loop_indices: Liste des index de boucle
Avoir
print("num of polygons:", len(msh.polygons))
for pl in msh.polygons:
print("polygon index:{0:2} ".format(pl.index), end="")
print("vertices:", end="")
for vi in pl.vertices:
print("{0:2}, ".format(vi), end="")
print("")
for pl in msh.polygons:
print("polygon index:{0:2} ".format(pl.index))
print(" > loops:", end="")
print(" total:", pl.loop_total, end="")
print(" start:", pl.loop_start, end="")
print(" indices:", end="")
for lp in pl.loop_indices:
print("{0:2}, ".format(lp), end="")
print("")
production
num of polygons: 6
polygon index: 0 vertices: 0, 1, 2, 3,
polygon index: 1 vertices: 0, 4, 5, 1,
polygon index: 2 vertices: 1, 5, 6, 2,
polygon index: 3 vertices: 2, 6, 7, 3,
polygon index: 4 vertices: 0, 3, 7, 4,
polygon index: 5 vertices: 4, 7, 6, 5,
polygon index: 0
> loops: total: 4 start: 0 indices: 0, 1, 2, 3,
polygon index: 1
> loops: total: 4 start: 4 indices: 4, 5, 6, 7,
polygon index: 2
> loops: total: 4 start: 8 indices: 8, 9, 10, 11,
polygon index: 3
> loops: total: 4 start: 12 indices:12, 13, 14, 15,
polygon index: 4
> loops: total: 4 start: 16 indices:16, 17, 18, 19,
polygon index: 5
> loops: total: 4 start: 20 indices:20, 21, 22, 23,
Données qui gèrent l'index des sommets et des arêtes. Il peut être utilisé lorsque vous souhaitez suivre les arêtes autour du polygone. Cependant, si vous souhaitez tracer correctement la contiguïté des sommets, des arêtes et des polygones, il est préférable de passer en mode Edition et d'utiliser Bmesh, donc je pense qu'il existe une telle propriété.
print("num of loops:", len(msh.loops))
for lp in msh.loops:
print("loop index:{0:2} vertex index:{1:2} edge index:{2:2}".format(lp.index, lp.vertex_index, lp.edge_index))
production
num of loops: 24
loop index: 0 vertex index: 0 edge index: 5
loop index: 1 vertex index: 1 edge index: 7
loop index: 2 vertex index: 2 edge index: 9
loop index: 3 vertex index: 3 edge index:10
loop index: 4 vertex index: 0 edge index:11
loop index: 5 vertex index: 4 edge index: 0
loop index: 6 vertex index: 5 edge index: 8
loop index: 7 vertex index: 1 edge index: 5
loop index: 8 vertex index: 1 edge index: 8
loop index: 9 vertex index: 5 edge index: 4
loop index:10 vertex index: 6 edge index: 3
loop index:11 vertex index: 2 edge index: 7
loop index:12 vertex index: 2 edge index: 3
loop index:13 vertex index: 6 edge index: 2
loop index:14 vertex index: 7 edge index: 1
loop index:15 vertex index: 3 edge index: 9
loop index:16 vertex index: 0 edge index:10
loop index:17 vertex index: 3 edge index: 1
loop index:18 vertex index: 7 edge index: 6
loop index:19 vertex index: 4 edge index:11
loop index:20 vertex index: 4 edge index: 6
loop index:21 vertex index: 7 edge index: 2
loop index:22 vertex index: 6 edge index: 4
loop index:23 vertex index: 5 edge index: 0
Définir et obtenir des UV est aussi simple que d'ajouter un canal UV et d'utiliser ce canal comme clé pour accéder à la matrice UV. Notez que les canaux affichés dans les UV Maps de l'interface graphique sont gérés par la propriété appelée uv_textures de Mesh, mais les informations de coordonnées UV réelles sont conservées par la propriété appelée uv_layers.
Il ne conserve pas une topologie différente pour chaque canal UV comme 3dsMax. Par conséquent, le nombre de coordonnées UV contenues dans chaque couche est toujours la somme du nombre de sommets de tous les polygones. Blender ne semble pas avoir de concepts tels que la soudure et le soudage dans les données.
>>> len(msh.uv_layers[channel_name].data.items())
24
#Réglage UV
tmp = [[0.0, 0.0], [0.5, 0.0], [0.5, 0.5], [0.0, 0.5]]
uvs = tmp * 6 #Initialiser les coordonnées UV à définir
channel_name = "uv0" #Nom du canal UV
msh.uv_layers.new(name=channel_name) #Création d'un canal UV
#msh.uv_textures.new(channel_name) #Création d'un canal UV
for idx, dat in enumerate(msh.uv_layers[channel_name].data): #Itérer avec un tableau de couches UV
dat.uv = uvs[idx]
Confirmation des données
print("num of uv layers:", len(msh.uv_layers))
#print("num of uv layers:", len(msh.uv_textures))
for ly in msh.uv_layerss:
#for ly in msh.uv_textures:
print(ly.name)
for idx, dat in enumerate(msh.uv_layers[ly.name].data):
print(" {0}:{1}".format(idx, dat.uv))
print("")
production
uv0
0:<Vector (0.0000, 0.0000)>
1:<Vector (0.5000, 0.0000)>
2:<Vector (0.5000, 0.5000)>
3:<Vector (0.0000, 0.5000)>
4:<Vector (0.0000, 0.0000)>
5:<Vector (0.5000, 0.0000)>
6:<Vector (0.5000, 0.5000)>
7:<Vector (0.0000, 0.5000)>
8:<Vector (0.0000, 0.0000)>
9:<Vector (0.5000, 0.0000)>
10:<Vector (0.5000, 0.5000)>
11:<Vector (0.0000, 0.5000)>
12:<Vector (0.0000, 0.0000)>
13:<Vector (0.5000, 0.0000)>
14:<Vector (0.5000, 0.5000)>
15:<Vector (0.0000, 0.5000)>
16:<Vector (0.0000, 0.0000)>
17:<Vector (0.5000, 0.0000)>
18:<Vector (0.5000, 0.5000)>
19:<Vector (0.0000, 0.5000)>
20:<Vector (0.0000, 0.0000)>
21:<Vector (0.5000, 0.0000)>
22:<Vector (0.5000, 0.5000)>
23:<Vector (0.0000, 0.5000)>
Vertex Color
Il est facilement accessible via la propriété vertex_colors.
Réglage
#6 côtés rouge, Green, Blue, Cyan, Magenta,Essayez de peindre avec du jaune
#colormaps = [[1.0,0.0,0.0]]*4+[[0.0,1.0,0.0]]*4+[[0.0,0.0,1.0]]*4+[[0.0,1.0,1.0]]*4+[[1.0,0.0,1.0]]*4+[[1.0,1.0,0.0]]*4
colormaps = [[1.0,0.0,0.0,1.0]]*4+[[0.0,1.0,0.0,1.0]]*4+[[0.0,0.0,1.0,1.0]]*4+[[0.0,1.0,1.0,1.0]]*4+[[1.0,0.0,1.0,1.0]]*4+[[1.0,1.0,0.0,1.0]]*4
print("colormaps:", colormaps)
msh.vertex_colors.new(name='col')
# msh.vertex_colors.new('col')
for idx, vc in enumerate(msh.vertex_colors['col'].data):
vc.color = colormaps[idx]
Obtenez des données
#Affichage de la couleur du sommet
print("num of vertex color layers:", len(msh.vertex_colors))
for ly in msh.vertex_colors:
print(ly.name)
for idx, vc in enumerate(msh.vertex_colors['col'].data):
print(" {0:2}:{1}".format(idx,vc.color))
production
num of vertex color layers: 1
col
0:<Color (r=1.0000, g=0.0000, b=0.0000)>
1:<Color (r=1.0000, g=0.0000, b=0.0000)>
2:<Color (r=1.0000, g=0.0000, b=0.0000)>
3:<Color (r=1.0000, g=0.0000, b=0.0000)>
4:<Color (r=0.0000, g=1.0000, b=0.0000)>
5:<Color (r=0.0000, g=1.0000, b=0.0000)>
6:<Color (r=0.0000, g=1.0000, b=0.0000)>
7:<Color (r=0.0000, g=1.0000, b=0.0000)>
8:<Color (r=0.0000, g=0.0000, b=1.0000)>
9:<Color (r=0.0000, g=0.0000, b=1.0000)>
10:<Color (r=0.0000, g=0.0000, b=1.0000)>
11:<Color (r=0.0000, g=0.0000, b=1.0000)>
12:<Color (r=0.0000, g=1.0000, b=1.0000)>
13:<Color (r=0.0000, g=1.0000, b=1.0000)>
14:<Color (r=0.0000, g=1.0000, b=1.0000)>
15:<Color (r=0.0000, g=1.0000, b=1.0000)>
16:<Color (r=1.0000, g=0.0000, b=1.0000)>
17:<Color (r=1.0000, g=0.0000, b=1.0000)>
18:<Color (r=1.0000, g=0.0000, b=1.0000)>
19:<Color (r=1.0000, g=0.0000, b=1.0000)>
20:<Color (r=1.0000, g=1.0000, b=0.0000)>
21:<Color (r=1.0000, g=1.0000, b=0.0000)>
22:<Color (r=1.0000, g=1.0000, b=0.0000)>
23:<Color (r=1.0000, g=1.0000, b=0.0000)>
Shape Key
C'est fondamentalement le même que le réglage UV. Contrairement à UV, la propriété shape_keys du maillage est responsable à la fois de la gestion des clés de forme et de la gestion des données des sommets. C'est la propriété key_blocks de la propriété shape_keys qui contient réellement les données.
Réglage
#Dans la variable verts définie lors de la création du cube(0,0,1), (0,0,-1)MoveUp chacun,Utilisez la touche Descendre
shapemaps = {'MoveUp':[[v[0],v[1],v[2]+1.0] for v in verts],
'MoveDown':[[v[0],v[1],v[2]-1.0] for v in verts],}
#Créer une clé de base s'il n'y a pas de forme
obj.shape_key_add()
msh.shape_keys.key_blocks[-1].name = "Basis"
for sname in shapemaps:
lst = shapemaps[sname]
obj.shape_key_add()
kb = msh.shape_keys.key_blocks[-1]
kb.name = sname
for idx, co in enumerate(lst):
kb.data[idx].co = co
Obtenez des données
#Obtenir la clé de forme
print("num of Shape Keys:", len(msh.shape_keys.key_blocks))
for kb in msh.shape_keys.key_blocks:
print(" Key Block:", kb.name)
for idx, dat in enumerate(kb.data):
print(" {0}:{1}".format(idx, dat.co))
production
num of Shape Keys: 3
Key Block: Basis
0:<Vector (-1.0000, -1.0000, 1.0000)>
1:<Vector (1.0000, -1.0000, 1.0000)>
2:<Vector (1.0000, 1.0000, 1.0000)>
3:<Vector (-1.0000, 1.0000, 1.0000)>
4:<Vector (-1.0000, -1.0000, -1.0000)>
5:<Vector (1.0000, -1.0000, -1.0000)>
6:<Vector (1.0000, 1.0000, -1.0000)>
7:<Vector (-1.0000, 1.0000, -1.0000)>
Key Block: MoveDown
0:<Vector (-1.0000, -1.0000, 0.0000)>
1:<Vector (1.0000, -1.0000, 0.0000)>
2:<Vector (1.0000, 1.0000, 0.0000)>
3:<Vector (-1.0000, 1.0000, 0.0000)>
4:<Vector (-1.0000, -1.0000, -2.0000)>
5:<Vector (1.0000, -1.0000, -2.0000)>
6:<Vector (1.0000, 1.0000, -2.0000)>
7:<Vector (-1.0000, 1.0000, -2.0000)>
Key Block: MoveUp
0:<Vector (-1.0000, -1.0000, 2.0000)>
1:<Vector (1.0000, -1.0000, 2.0000)>
2:<Vector (1.0000, 1.0000, 2.0000)>
3:<Vector (-1.0000, 1.0000, 2.0000)>
4:<Vector (-1.0000, -1.0000, 0.0000)>
5:<Vector (1.0000, -1.0000, 0.0000)>
6:<Vector (1.0000, 1.0000, 0.0000)>
7:<Vector (-1.0000, 1.0000, 0.0000)>
Vertex Group
Je pense que ce sont les données les plus simples, mais c'est la structure de données la plus gênante. Blender détient le poids de la peau dans ce groupe Vertex. Par conséquent, les données sont conservées sous forme de tableau associatif avec l'indice du groupe de sommets comme clé et le poids comme valeur pour chaque sommet. Une fonction pour définir le poids des sommets est fournie dans la structure du groupe de sommets afin qu'il puisse être défini comme s'il s'agissait d'UV. Je ne pense pas que la vitesse de traitement soit rapide.
Réglage
bone_list = ["bone1", "bone2"]
weight_map = {"bone1":[1.0]*4+[0.0]*4, # [1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0],
"bone2":[0.0]*4+[1.0]*4,
}
vg_list = [] #Liste des VertexGroup
#Créer un groupe de sommets
for bname in bone_list:
obj.vertex_groups.new(name=bname)
#obj.vertex_groups.new(bname)
vg_list.append(obj.vertex_groups[-1])
#Paramètres via Vertex Group
for vg in vg_list:
weights = weight_map[vg.name]
for vidx, w in enumerate(weights):
if w != 0.0:
vg.add([vidx], w, 'REPLACE')
Essayez d'obtenir les données via les propriétés des sommets.
Obtenez des données
#Obtenir du poids via la propriété groupes de Vertex
msh = obj.data
for v in msh.vertices:
for vge in v.groups:
print("vindex:{0} group index:{1} weight:{2}".format(v.index, vge.group, vge.weight))
production
vindex:0 group index:0 weight:1.0
vindex:1 group index:0 weight:1.0
vindex:2 group index:0 weight:1.0
vindex:3 group index:0 weight:1.0
vindex:4 group index:1 weight:1.0
vindex:5 group index:1 weight:1.0
vindex:6 group index:1 weight:1.0
vindex:7 group index:1 weight:1.0
Les données de collection telles que la propriété data de uv_layer ont une fonction appelée foreach_set, et vous pouvez définir la valeur en une seule fois avec un tableau. Il n'a pas été vérifié s'il est plus rapide que d'itérer les séquences normalement et de les affecter une par une. Notez que cette méthode passera un tableau ordinaire qui est aplati au lieu du tableau du tableau ci-dessus.
python
tmp = [0.0, 0.0, 0.5, 0.0, 0.5, 0.5, 0.0, 0.5]
uvs = tmp * 6 #Initialiser les coordonnées UV à définir
channel_name = "uv0"
msh.uv_textures.new(channel_name)
msh.uv_layers[channel_name].data.foreach_set("uv", uvlist)
python
shapemaps = {'MoveUp':[[v[0],v[1],v[2]+1.0] for v in verts],
'MoveDown':[[v[0],v[1],v[2]-1.0] for v in verts],}
for sname in shapemaps:
lst = shapemaps[sname]
lst2 = list(chain.from_iterable(lst)) #Cela semble être plus rapide avec la méthode d'aplatissement du tableau de tableaux
obj.shape_key_add()
sk = msh.shape_keys.key_blocks[-1]
sk.name = sname
sk.data.foreach_set("co", lst2)
Recommended Posts