Spelunking the Blender Data Model - BadDogSkyrim/PyNifly GitHub Wiki

This page collects notes and discoveries about using Blender through the python API.

Custom normals and split normals

There's one normal associated with each vertex, which appears to average the face normals. "Smooth shading" on the model ends up using this normal. These are calculated with mesh.calc_normals(). Blender does the calc when it needs to; you need to call it explicitly before depending on the normals.

The calculation has to be done in object mode.

Split normals are stored on the mesh loops, which means there's one for each face-on-vertex. A vertex at the corner of 3 faces will have 3 split normals if the edges are sharp. These have to be calculated before they will be correct, using mesh.calc_normals_split().

Custom normals are also stored on loops, added on as a layer of some sort [TBS]. This can be seen in the mesh properties panel, Geometry Data, where you can add or remove custom split normals. mesh.has_custom_normal() will indicate whether there are custom normals, but you can have split normals without custom normals.

The Data Transform modifier and operator can transfer normals from one shape to another. It's called "Custom Normals" in the UI because that's how the result is stored. Note the operator works backwards -- the active object (selected last) is the source of the normals.

A BMesh will give you access to the custom normals and they will be wrong. I haven't figured out how to get correct normals through a BMesh.

Perhaps the normals need to be calculated on the mesh before generating the bmesh.

Triangulating meshes

BMesh will do it, but it will create very odd split normals.

There's an operator for it, bpy.ops.mesh.quads_convert_to_tris(). It will nuke the normals, so they have to be recalculated afterwards. It has to be run in edit mode. It runs on the current active object and the currently selected faces. Faces have to be selected in object mode.

bpy.ops.object.mode_set()

  • Requires an active object, or it fails its poll.

Shape Keys and Vertex Position

How shape keys are reflected in the vertex position (Obj.data.vertices) is tricky. If an object has an active shape key (obj.active_shape_key_index != 0), there's no guarantee the vertex positions will be correct, for either the base shape or the active shape. The only way I've found to make them correct is by making the base shape active, going into edit mode and then back to object mode, which seems to force an internal reset.

Vertex Colors

Have to be in object mode to get vertex colors.