# How to convert coordinates from vertex to world-space?

How do I convert from object-space to world-space?

I suspect it is:

vert_os = obj.vertices[foo]
vert_ws = vert_os.getPositionFromMatrix(obj.matrixWorld)


but does the matrix also handle translations, or do I need to handle that separately?

Can someone link to the relevant documentation?

Multiply the world matrix by the object-space vector for world space coordinate:

import bpy

ob = bpy.data.objects['Cube']

v = ob.data.vertices[0].co
mat = ob.matrix_world

loc = mat @ v

# Don't do the reverse!
loc = v @ mat  # wrong!


Object.matrix_world is a 4x4 transformation matrix. It contains translation, rotation and scale. A 4x4 matrix can also be used for mirroring and shearing (not covered in my answer).

[a] [b] [c] [d]
[e] [f] [g] [h]
[i] [j] [k] [l]
[m] [n] [o] [p]


The translation is stored in the first 3 rows of the 4th column of the matrix (d, h, l):

mat.col[3][:3]


You can also use:

# Create new Vector object
mat.to_translation()

# Access the original matrix' translation
# (assignments will change the matrix, thus the object location!)
mat.translation


Rotation and scale are sort of combined. The rotation is stored in a, b, c, e, f, g, i, j and k. The scale is stored in a, f and k. The values in a, f and k of the rotation are taken and multiplied by the scale factor to store both pieces of information.

To get only the rotation, you need to normalize the 3x3 matrix:

mat.to_3x3().normalized()


To get only the scale, you can use the utility method:

mat.to_scale()


Or manually, normalize the matrix and divide each of the un-normalized by the normalized components (a, f, k):

# you could do this manually like
# vec / sqrt(vec.x**2 + vec.y**2 + vec.z**2) for every matrix column
nmat = mat.normalized()

scale = Vector((mat[0][0] / nmat[0][0], mat[1][1] / nmat[1][1], mat[2][2] / nmat[2][2]))


If you need the world coordinates of all vertices, it's more efficient to use the transform() method:

me.transform(mat)


It will apply the transformation matrix to the mesh, so multiply the world matrix with all vertex coordinates. You may wonder about the change in orientation of a mesh object in viewport if you do the above. It can be fixed by resetting the matrix_world (otherwise the transformation will be done twice):

ob.matrix_world = Matrix()  # identity matrix

• Maybe you mean v = ob.data.vertices[0].co instead of v = ob.data.vertices[0].
– isar
Commented Jul 5, 2015 at 19:25
• Love how "translation stored in d, h, l" — could be a tagline for DHL :D Commented Feb 5, 2021 at 15:48

This is fairly simple and applies to any data (curves, armatures, lattice ...)

v_co_world = obj.matrix_world @ obj.data.vertices[0].co


Its also handy to be able to do the reverse, get a point in worldspace relative to the vertex.

# get the cursor in object space
# (so you can compare it to the vertices locations
#  without first having to transform them into worldspace).
v_co_object = obj.matrix_world.inverted() @ scene.cursor_location

• For me, the camera's matrix_world was an identity matrix, so to get the coordinates of a point relative to the camera, I needed camera.matrix_basis.inverted() * mathutils.Vector([0,0,0]) Commented Apr 12, 2019 at 22:06

In blender 2.8 use @ operator for matrix multiplication

for example

transformed_vertex =obj.matrix_world @ obj.data.vertices[0].co

• I'm using Blender 2.8--this worked for me without importing NumPy. Using * failed. Commented May 23, 2019 at 22:27
• @ is a operator in python. For more info PEP465 Commented May 30, 2019 at 8:26

If you're brave enough to use numpy you can get all the vertex coords as a numpy array about a thousand times as fast as any other python method:

import numpy as np

def get_co(ob, arr=None):
"""Returns vertex coords as N x 3"""
c = len(ob.data.vertices)
if arr is None:
arr = np.zeros(c * 3, dtype=np.float32)
ob.data.vertices.foreach_get('co', arr.ravel())
arr.shape = (c, 3)
return arr

def get_proxy_co(ob, arr):
"""Returns vertex coords with modifier effects as N x 3"""
me = ob.to_mesh(bpy.context.scene, True, 'PREVIEW')
c = len(me.vertices)
me.vertices.foreach_get('co', arr.ravel())
bpy.data.meshes.remove(me)
arr.shape = (c, 3)
return arr

def apply_transforms(ob, co):
"""Get vert coords in world space"""
m = np.array(ob.matrix_world)
mat = m[:3, :3].T # rotates backwards without T
loc = m[:3, 3]
return co @ mat + loc

def revert_transforms(ob, co):
"""Set world coords on object.
Run before setting coords to deal with object transforms
if using apply_transforms()"""
m = np.linalg.inv(ob.matrix_world)
mat = m[:3, :3].T # rotates backwards without T
loc = m[:3, 3]
return co @ mat + loc

• A thousand times faster? Commented Sep 20, 2017 at 5:52
• I just did a speed check. against loop and list comprehension. on an object with 60,000 verts, numpy was only 20 times faster. Sorry about the exaggeration. Commented Sep 20, 2017 at 17:03
• 20 is still good. Care to add test result to answer? Commented Sep 20, 2017 at 17:06
• I'm not good at posting here. Is there a way I can send you my code? Commented Sep 20, 2017 at 17:09
• I posted the code on git link Commented Sep 21, 2017 at 17:48

If you have your coords in a flat numpy.array from foreach_get("co", coords), the following dot product of the world matrix with the local coordinates will get their their global version:

import numpy as np

def to_global(local_coords, world_matrix):

# Reshape coords to Nx3 matrix
local_coords.shape = (-1, 3)

# Add an extra 1.0s column (for matrix dot product)
local_coords = np.c_[local_coords, np.ones(local_coords.shape[0])]

# Then:
# Dot product matrix with the coords transpose
# Keep the first 3 rows (x,y,z)
# Transpose result to Nx3
# Flatten
global_coords = np.dot(world_matrix, local_coords.T)[0:3].T.reshape((-1))

return global_coords


To use:

# Get the local coords
local_coords = np.zeros(len(my_obj.data.vertices) * 3)
my_obj.data.vertices.foreach_get('co', local_coords)

# Convert to global
global_coords = to_global(local_coords, my_obj.matrix_world)


On my machine and a mesh with 491,526 verts, the function takes 8.1 ms, or about 0.16ms per 10k verts:

>>> timeit.timeit(lambda: to_global(local_coords, my_obj.matrix_world), number=1000) / 1000.0
0.008153792893048377

import bpy

obj = bpy.data.objects['Cube']

wm = obj.matrix_world
print( wm )
for v in obj.data.vertices:
world = wm * v.co
print(world)
`

The world matrix contains the transformations for location,rotation and scale as in the Properties Panel:

The relevant documentation on Math Types & Utilities mathutils