[PYTHON] Follow Blender's data structure and extract vertex coordinates from fbx

Using Blender, I created a script that extracts only the vertex coordinates from the FBX data and arranges them, so I will introduce it after the explanation.

Blender data structure

First of all, about this familiar figure (initial state).

image.png

Now, Blender's 3D view is managed in the following way.

image.png

In Python script

bpy.context.scene.collection

This is where it corresponds.

image.png

This is the GUI.

There is a scene → collection at the origin, and there are objects in the collection. I don't really understand the difference between a scene and a collection. However, objects (so-called cubes, cameras, etc.) that exist as data are called into the collection by linking them. This means that only linked objects will appear in the view, and ** objects that are invisible but exist as data **. By doing this, it seems that the same data is used. It's complicated for those who operate it.

And like objects, the meshes and materials that accompany them also have a data list that you can link to use as much as you need.

For example, here

bpy.data.objects.new("hoge", bpy.data.meshes.new("fuga"))

Does not change anything in the apparent scene,

for i in bpy.data.objects:
    print(i)

so,

Output


<bpy_struct, Object("Camera")>
<bpy_struct, Object("Cube")>
<bpy_struct, Object("hoge")>
<bpy_struct, Object("Light")>

Is returned, so you can see that a mysterious object called hoge has been added. Also,

bpy.data.objects['hoge'].to_mesh()

so,

Output


bpy.data.meshes['fuga']

You can see that this object is linked to a mesh called fuga. Of course, this is just empty data with a name, so if you link hoge to the collection now, it will summon nothing with a name that has no vertices.

Take a closer look at the mesh. The vertex information of the mesh is managed in the following form.

image.png

The object is linking the mesh.

image.png

This is the GUI.

The mesh data also stores vertex data, so if you want vertex information, you will access it. Now let's target the cubes that have a proper shape.

bpy.data.objects['Cube'].to_mesh().vertices

This is almost the same as the picture above.

Output


bpy.data.meshes['Cube'].vertices

Looking at this content,

for i in bpy.data.meshes['Cube'].vertices:
    print(i)

Output


<bpy_struct, MeshVertex at 0x0000024A9FA28038>
<bpy_struct, MeshVertex at 0x0000024A9FA2804C>
<bpy_struct, MeshVertex at 0x0000024A9FA28060>
<bpy_struct, MeshVertex at 0x0000024A9FA28074>
<bpy_struct, MeshVertex at 0x0000024A9FA28088>
<bpy_struct, MeshVertex at 0x0000024A9FA2809C>
<bpy_struct, MeshVertex at 0x0000024A9FA280B0>
<bpy_struct, MeshVertex at 0x0000024A9FA280C4>

Binary data is returned earnestly. Since there are 8 properly, it seems that there is no mistake in the cube, but I would like you to return the numerical value if possible. If you look at Reference, you can see that the value can be obtained with the attribute co.

for i in bpy.data.meshes['Cube'].vertices:
    print(i.co)

Output


<Vector (1.0000, 1.0000, 1.0000)>
<Vector (1.0000, 1.0000, -1.0000)>
<Vector (1.0000, -1.0000, 1.0000)>
<Vector (1.0000, -1.0000, -1.0000)>
<Vector (-1.0000, 1.0000, 1.0000)>
<Vector (-1.0000, 1.0000, -1.0000)>
<Vector (-1.0000, -1.0000, 1.0000)>
<Vector (-1.0000, -1.0000, -1.0000)>

Now we finally have an array of vertex coordinates.

Applies to fbx

Do the same for the imported fbx.

image.png

In principle, you should get the same shape as above by extracting the vertices for all the mesh data.

for i in bpy.data.meshes:
    print(i)

Output


<bpy_struct, Mesh("Cube")>
<bpy_struct, Mesh("Mesh")>
<bpy_struct, Mesh("Mesh.001")>
<bpy_struct, Mesh("Mesh.002")>
<bpy_struct, Mesh("Mesh.003")>
<bpy_struct, Mesh("Mesh.004")>
<bpy_struct, Mesh("Mesh.005")>
<bpy_struct, Mesh("Mesh.006")>
<bpy_struct, Mesh("Mesh.007")>

……. There is a mysterious Cube. Yes, ** the first cube that exists when you launch Blender **. Even if you delete it from the scene (unlink to be exact), the data inside will not disappear. If nothing is done, it will pick up to the top of the cube. Let's have it disappear.

bpy.data.meshes.remove(bpy.data.meshes['Cube'])
for i in bpy.data.meshes:
    print(i)

Output


<bpy_struct, Mesh("Mesh")>
<bpy_struct, Mesh("Mesh.001")>
<bpy_struct, Mesh("Mesh.002")>
<bpy_struct, Mesh("Mesh.003")>
<bpy_struct, Mesh("Mesh.004")>
<bpy_struct, Mesh("Mesh.005")>
<bpy_struct, Mesh("Mesh.006")>
<bpy_struct, Mesh("Mesh.007")>

It has disappeared. After that, write a script that extracts the vertex coordinates for all of these mesh data.

import bpy
import numpy as np

vts = []

for m in bpy.data.meshes:
    for v in m.vertices:
        vts.append(v.co)

vts = np.array(vts)

Since the number obtained by co is of type Vector, it is converted by np.array for ease of handling.

Let's verify that the array obtained here really represents the original shape. If the vertices hold the 3D information accurately, a scatter plot should show the original shape.

The array vts obtained earlier

np.savetxt(r'Arbitrary path\vts.txt', vts)

Export with. Draw a scatter plot in another Python file (because Blender's built-in Python doesn't have matplotlib ...).

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

data = np.loadtxt('vts.txt')

X = data[:,0]
Y = data[:,1]
Z = data[:,2]

fig = plt.figure()
ax = Axes3D(fig)
ax.set_xlabel("X")
ax.set_ylabel("Y")
ax.set_zlabel("Z")
ax.plot(X,Y,Z,marker="o",linestyle='None',ms=0.2)

plt.show()

image.png

It turns out that the vertices of the original 3D data can be accurately arrayed.

Recommended Posts

Follow Blender's data structure and extract vertex coordinates from fbx
Extract data from S3
Extract csv data and calculate
Extract specific data from complex JSON
Persistent data structure created from scratch
Extract Pokemon GO Pokemon data and skill data
Extract and plot the latest population data from the PDF data provided by the city
Make a decision tree from 0 with Python and understand it (4. Data structure)
Python data structure and internal implementation ~ List ~
Python data structure and operation (Python learning memo ③)