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?


6 Answers 6


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

# Multiply matrix by vertex (see also: https://developer.blender.org/T56276)
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):


You can also use:

# Create new Vector object

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

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:


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


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:


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
  • $\begingroup$ Maybe you mean v = ob.data.vertices[0].co instead of v = ob.data.vertices[0]. $\endgroup$
    – isar
    Jul 5, 2015 at 19:25
  • 1
    $\begingroup$ Love how "translation stored in d, h, l" — could be a tagline for DHL :D $\endgroup$ 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
  • $\begingroup$ 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]) $\endgroup$
    – colllin
    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
  • $\begingroup$ I'm using Blender 2.8--this worked for me without importing NumPy. Using * failed. $\endgroup$ May 23, 2019 at 22:27
  • 2
    $\begingroup$ @ is a operator in python. For more info PEP465 $\endgroup$ 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())
    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
  • $\begingroup$ A thousand times faster? $\endgroup$
    – batFINGER
    Sep 20, 2017 at 5:52
  • 2
    $\begingroup$ 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. $\endgroup$ Sep 20, 2017 at 17:03
  • $\begingroup$ 20 is still good. Care to add test result to answer? $\endgroup$
    – batFINGER
    Sep 20, 2017 at 17:06
  • $\begingroup$ I'm not good at posting here. Is there a way I can send you my code? $\endgroup$ Sep 20, 2017 at 17:09
  • 1
    $\begingroup$ I posted the code on git link $\endgroup$ 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
import bpy

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

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

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

enter image description here

The relevant documentation on Math Types & Utilities mathutils


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.