Skip to content

Instantly share code, notes, and snippets.

@michalpelka
Last active October 4, 2022 20:49
Show Gist options
  • Select an option

  • Save michalpelka/6f17e51547948ccb2cd8d50c7b611a42 to your computer and use it in GitHub Desktop.

Select an option

Save michalpelka/6f17e51547948ccb2cd8d50c7b611a42 to your computer and use it in GitHub Desktop.
Find a Object Oriented Bouding Box (OOBB) in Blender
# This example assumes we have a mesh object selected
import bpy
import bmesh
import numpy as np
def getCentroid(A):
return np.mean(A,axis=0)
def getSE3FromPointcloud(A):
A = np.array(A)
print (A.shape)
cen = getCentroid(A)
cov = A - cen
print ("centroid %s" % (cen))
u,s,vh = np.linalg.svd(cov, full_matrices=True)
np.set_printoptions(suppress=True)
return ((vh[0,0],vh[0,1],vh[0,2],cen[0]),
(vh[1,0],vh[1,1],vh[1,2],cen[1]),
(vh[2,0],vh[2,1],vh[2,2],cen[2]),
(0,0,0,1))
def findAABB(found_SE3, A):
D = []
found_SE3 = np.array(found_SE3)
found_SE3_i = np.linalg.inv(found_SE3)
for p in A:
D.append(found_SE3_i@[p[0],p[1],p[2],1])
print(np.around(D,decimals=3))
co_min = np.min(D, axis=0)[0:3]
co_max = np.max(D, axis=0)[0:3]
diff = (co_max - co_min)*0.5
return np.flip(np.sort(diff))
A = np.array(A)
print (A.shape)
cen = getCentroid(A)
cov = A - cen
print ("centroid %s" % (cen))
u,s,vh = np.linalg.svd(cov, full_matrices=True)
np.set_printoptions(suppress=True)
return ((u[0,0],u[0,1],u[0,2],cen[0]),
(u[1,0],u[1,1],u[1,2],cen[1]),
(u[2,0],u[2,1],u[2,2],cen[2]),
(0,0,0,1))
if __name__=="__main__":
# get active object
obj = bpy.context.active_object
# get its vertices in world coordinate system
A = []
for v in obj.data.vertices:
co_final = obj.matrix_world @ v.co
A.append([co_final.x,co_final.y,co_final.z])
nn = obj.name+"_svd "
if nn in bpy.data.objects:
empty = bpy.data.objects[nn]
else:
empty = bpy.data.objects.new( nn, None )
empty.empty_display_size = 1
empty.empty_display_type = 'CUBE'
bpy.context.collection.objects.link(empty)
found_SE3 = getSE3FromPointcloud(A)
# apply rotation (it should apply translation as well, but it is not
empty.matrix_world = found_SE3
# apply translation
empty.location = getCentroid(A)
scale = findAABB(empty.matrix_world , A)
print ("AABB :",np.around(scale,decimals=3))
empty.scale.x = scale[0]
empty.scale.y = scale[1]
empty.scale.z = scale[2]
print ("Done")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment