Geometry origin for export

I’m in the process of writing an exporter. I can get an object’s transform and I can get an object’s vertices, but I can’t seem to get where these vertices are relative to.

If I do something like this… = object
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')

Then I know the vertices are relative to the center. But an exporter shouldn’t be modifying the scene.

Is there a “read only” way to get the relationship between the vertices and the object’s origin?

The object transform and mesh vertex locations is all there is. The origin is simply defined as 0,0,0 in object space. Transforming 0,0,0 to world space then equals the object location.

Thank you for the response.

That doesn’t seem to be the case though. Here is an example.

In this case, the origin of the mesh is near one edge. The min/max values of the vertices are (-2.333, -2.333, -2.333)(2.365, 2.365, 2.365). The object location is (-0.022, 2.107, 0.0).

With an origin of (0, 0, 0), I would expect that the min Y of the vertices would be closer to 0.

If I perform bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN') then the min/max values change to (-2.348, -2.348, -2.348)(2.35, 2.35, 2.35) and the location changes to (-0.007, 0.154, 0.576). So there is definitely a 3rd value since bpy.ops.object.origin_set used it to calculate the other values.

There is a bpy.ops.object.origin_set and bpy.ops.object.origin_clear but I don’t see any bpy.ops.object.origin_get. But the value must be stored somewhere.

The mesh object here seems to be instanced by a group object. That means the effective object location is not just the Location displayed in the Transform panel, but also is affected by the transform of the group object.

If you’re exporting scenes like this you likely want to iterate over object instances and use their transform (object_instance.matrix_world), rather than the original object’s transform.

1 Like

I checked and is_instance is False.

The mesh object has a matrix_basis, matrix_local, and matrix_world that are all as follows…

Matrix(((1.0, 0.0, 0.0, -0.0221950002014637), (0.0, 1.0, 0.0, 2.106674909591675), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0))

So as I mentioned above, the position is (-0.022, 2.107, 0.0).

There is one parent, and that matrix is identity…

Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0)))

So the local position and world position are the same in this case.

But I’m not interested in the world space position of the object. I’m looking for the object space positions of the vertices. The vertices are not in object space, they are in origin space.

Here is a simpler example. The matrices for all object are now identity. We no longer need to talk about object positions, since everything is at (0, 0, 0).

The vertex values are still between (-2.333, -2.333, -2.333) and (2.365, 2.365, 2.365) so the origin is clearly not (0, 0, 0).

If it’s using parenting and not instancing, then perhaps this is what you are missing:

However in general for exporters you should be using matrix_world since it contains all the transforms from animation, parenting, instancing, constraints, rigid body simulation, etc.

Thank you for the page, but that is still information about object transforms. That is not my issue.

In the second screenshot I provided above, A vertex exists with the Y value of 2.365 that is being rendered at the Y location of 0 (approximately).

It’s not the object position I want. I’m looking for the vertex positions that are relative to the axis that is displayed in the second screenshot.

I don’t know what to say, the origin you are looking for simply does not exist in Blender. Most likely matrix_world is not the identity matrix and is transforming this vertex.

I am 100% positive it exists. Did you look at the second screenshot I posted?

Here is the doc for bpy.ops.object.origin_set:

Set the object’s origin, by either moving the data, or set to center of data, or use 3D cursor

This proves that there exists an origin. The UI uses the term axis. Either way, this value exists in Blender.

Vertices are relative to this origin or axis which could be placed at a position, either relative to a parent object (local position) or to the world (world position).

But it isn’t simply isn’t enough to know a vertex is located at (2.35, 2.35, 2.35) and the object is located at (0, 0, 0) without knowing the origin.

All the set origin operator does is move the object’s transform and then move the vertex positions in the opposite direction so that they stay in the same location in world space. So yeah, the origin of an object’s geometry is just the same thing as the location of its transform.

1 Like

I made the screenshot even easier to understand.

  • There is just one object with no parent, modifiers, or constraints.
  • The Y axis is the green line.
  • The X axis is the red line.
  • Where the X and Y meet is 0, 0, 0 as shown by a little red and white circle.
  • The location of the object as shown in the screenshot is X=0m, Y=0m, Z=0m.
  • The matrix_world property for the object in Python is Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0))).
  • The matrix_local property for the object in Python is Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0))).
  • The matrix_basis property for the object in Python is Matrix(((1.0, 0.0, 0.0, 0.0), (0.0, 1.0, 0.0, 0.0), (0.0, 0.0, 1.0, 0.0), (0.0, 0.0, 0.0, 1.0))).
  • The min and max values for the vertex positions (data.vertices[].co) are (-2.333, -2.333, -2.333) and (2.365, 2.365, 2.365).
  • The orange lines represent the bounding box of the mesh.
  • Based on the grid, the positive Y of the bounding box is at 0.05 (approximately).
  • Since 2.365 != 0.5, there must be an offset, origin point, pivot point, or whatever you want to call it that Blender uses to transform 2.365 to 0.5.

Please share the .blend file. Screenshots won’t help showing what is going on.

Here is the file…

Can you tell us how you got those numbers? Because I am getting 0.0531 for the y min and -4.1410 for the y max.

>>> print(min([ for v in D.objects['col'].data.vertices]))

>>> print(max([ for v in D.objects['col'].data.vertices]))

And those values won’t change, when the object is transformed. Because the objects origin is always (0,0,0) in object space.

EDIT: It looks like you maybe used the x min and x max for x,y, and z?

Thank you for looking at the file.

You are correct, I mistakenly used the X for all three values when I made the example asset.

I’m still seeing any offset when I export though, so I guess I’ll continue to look why this is the case.

I think I found it. There is also a delta_location which is separate from location, which seems to be causing the extra offset in my main asset. How does the relate to the various matrices? I don’t see a matrix_delta

While trying to narrow it down with an example, I made the problem worse. Sorry for the confusion.

Delta transforms are part of matrix_world just like parenting, instancing, constraints, rigid body simulation, etc. In general exporters should just use that matrix + mesh vertex positions and not be aware of all the ways Blender can transform objects.

Thank you for the information.

In this particular exporter, I need vertex positions in world space plus the parent relative object graph for animation. The delta transforms in this case are important since the pivot location may not be centered in the mesh.

With the combination of the object transform, delta transform, and world matrix transformed vertex positions I am now able to get the correct exported results.

I appreciate the help.