Skip to content
Closed

Dev #24

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
11ef1af
1.align_pick_points.py
huiyao8761380 Aug 30, 2019
0455e66
1align_pick_points.py
huiyao8761380 Aug 30, 2019
6bbd12d
Delete align_pick_points.py
huiyao8761380 Aug 30, 2019
f6aa117
2.79
huiyao8761380 Aug 31, 2019
3b5173f
Merge pull request #2 from huiyao8761380/2.79
huiyao8761380 Aug 31, 2019
f4366a1
Merge pull request #3 from huiyao8761380/master
huiyao8761380 Aug 31, 2019
ca3be13
Merge pull request #16 from huiyao8761380/ICPfor2.8API
patmo141 Aug 31, 2019
f3b78dd
citation.text started
patmo141 Aug 31, 2019
7df7b85
try some things
patmo141 Aug 31, 2019
e887fb3
Merge branch 'b_280' of https://github.com/patmo141/object_alignment …
patmo141 Aug 31, 2019
f606a29
matrix multiplication
patmo141 Aug 31, 2019
10c0cb8
matrix multiplication
patmo141 Aug 31, 2019
d0d74cb
comment out until future api knowledge replaces
patmo141 Aug 31, 2019
c483f74
scene update changes
patmo141 Aug 31, 2019
61fbe04
active object
patmo141 Aug 31, 2019
b382843
depsgraph update
patmo141 Aug 31, 2019
fe1332c
eval depsgraph
patmo141 Aug 31, 2019
4d8a522
matrix multiplication
patmo141 Aug 31, 2019
3b4aded
280 api
patmo141 Aug 31, 2019
e085372
2.80 api changes
patmo141 Aug 31, 2019
7415a86
get point labels back
patmo141 Aug 31, 2019
1d56ee1
hack to collapse the dead screen? may cause crashes
patmo141 Aug 31, 2019
755ff89
attempt 3d drawing with crude shader
patmo141 Aug 31, 2019
3262b80
dont draw before shaders are iniitialized
patmo141 Aug 31, 2019
2907eb1
actually create the batches once points are clicked
patmo141 Aug 31, 2019
0e66240
typo
patmo141 Aug 31, 2019
6c969ed
typo
patmo141 Aug 31, 2019
aa987e5
code examples for later
patmo141 Sep 2, 2019
7b2da1f
test updates to area split and merge code
patmo141 Mar 15, 2020
a859188
Merge branch 'b_280' of https://github.com/patmo141/object_alignment …
patmo141 Mar 15, 2020
e688b6c
Merge branch 'b_280' of https://github.com/patmo141/object_alignment …
patmo141 Mar 15, 2020
ee5785a
need to do context override after taking objects to local view
patmo141 Mar 15, 2020
fd3b4fe
Fixed typo in icp_align polling function
FredericNk Apr 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions citation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Original Papers First introduced by Chen and Medioni (1991) and Besl and McKay (1992).


1. Chen, Yang; Gerard Medioni (1991).
"Object modelling by registration of multiple range images".
Image Vision Comput.
10 (3): 145�155. doi:10.1016/0262-8856(92)90066-C.

2. Besl, Paul J.; N.D. McKay (1992).
"A Method for Registration of 3-D Shapes".
IEEE Transactions on Pattern Analysis and Machine Intelligence.
14 (2): 239�256. doi:10.1109/34.121791.

3.Transformations Python Library
Author: Christoph Gohlke <https://www.lfd.uci.edu/~gohlke/>`_
Organization: Laboratory for Fluorescence Dynamics. University of California, Irvine
https://www.lfd.uci.edu/~gohlke/code/transformations.py.html

4. FINDING OPTIMAL ROTATION AND TRANSLATION BETWEEN CORRESPONDING 3D POINTS
Author: Nghia Ho, nghiaho12@yahoo.com
Organization:
https://nghiaho.com/?page_id=671
http://nghiaho.com/uploads/code/rigid_transform_3D.py

5. Blender Implementation, Filtering Code, UI, BVH Acceleration
Modal Operator
Patrick Moore: patrick.moore.bu@gmail.com
working as a hobby and later update for D3tool.com


### Add Additional Citation Below ###
6 changes: 3 additions & 3 deletions functions/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def make_pairs(align_obj, base_obj, base_bvh, vlist, thresh, sample = 0, calc_st

vert = align_obj.data.vertices[vert_ind]
#closest point for point clouds. Local space of base obj
co_find = imx2 * (mx1 * vert.co)
co_find = imx2 @ (mx1 @ vert.co)

#closest surface point for triangle mesh
#this is set up for a well modeled aligning object with
Expand All @@ -285,12 +285,12 @@ def make_pairs(align_obj, base_obj, base_bvh, vlist, thresh, sample = 0, calc_st
#res, co1, normal, face_index = base_obj.closest_point_on_mesh(co_find)
co1, n, face_index, d = base_bvh.find_nearest(co_find)

dist = (mx2 * co_find - mx2 * co1).length
dist = (mx2 @ co_find - mx2 @ co1).length
#d is now returned by bvh.find
#dist = mx2.to_scale() * d
if face_index != -1 and dist < thresh:
verts1.append(vert.co)
verts2.append(imx1 * (mx2 * co1))
verts2.append(imx1 @ (mx2 @ co1))
if calc_stats:
dists.append(dist)

Expand Down
10 changes: 5 additions & 5 deletions functions/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def draw_3d_points_revised(context, points, color, size):

for vec in points:

vec_4d = perspective_matrix * vec.to_4d()
vec_4d = perspective_matrix @ vec.to_4d()
if vec_4d.w > 0.0:
x = region_mid_width + region_mid_width * (vec_4d.x / vec_4d.w)
y = region_mid_height + region_mid_height * (vec_4d.y / vec_4d.w)
Expand All @@ -87,7 +87,7 @@ def draw_3d_text(context, font_id, text, vec):
region_mid_height = region.height / 2.0

perspective_matrix = region3d.perspective_matrix.copy()
vec_4d = perspective_matrix * vec.to_4d()
vec_4d = perspective_matrix @ vec.to_4d()
if vec_4d.w > 0.0:
x = region_mid_width + region_mid_width * (vec_4d.x / vec_4d.w)
y = region_mid_height + region_mid_height * (vec_4d.y / vec_4d.w)
Expand Down Expand Up @@ -117,8 +117,8 @@ def get_ray_origin(ray_origin, ray_direction, ob):
if abs(ray_direction.x)>0.0001: planes += [(bm,x), (bM,-x)]
if abs(ray_direction.y)>0.0001: planes += [(bm,y), (bM,-y)]
if abs(ray_direction.z)>0.0001: planes += [(bm,z), (bM,-z)]
dists = [get_ray_plane_intersection(ray_origin,ray_direction,mx*p0,q*no) for p0,no in planes]
return ray_origin + ray_direction * min(dists)
dists = [get_ray_plane_intersection(ray_origin,ray_direction,mx@p0,q@no) for p0,no in planes]
return ray_origin + ray_direction @ min(dists)

# Jon Denning for Retopoflow
def ray_cast_region2d(region, rv3d, screen_coord, obj):
Expand All @@ -139,7 +139,7 @@ def ray_cast_region2d(region, rv3d, screen_coord, obj):
bver = '%03d.%03d.%03d' % (bpy.app.version[0],bpy.app.version[1],bpy.app.version[2])
if (bver < '002.072.000') and not rv3d.is_perspective: mult *= -1

st, en = imx*(o-mult*back*d), imx*(o+mult*d)
st, en = imx@(o-mult*back*d), imx@(o+mult*d)

if bversion() < '002.077.000':
hit = obj.ray_cast(st,en)
Expand Down
135 changes: 105 additions & 30 deletions operators/align_pick_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#https://cognitivewaves.wordpress.com/opengl-vbo-shader-vao/#shader-with-vertex-buffer-object

# System imports
import time
Expand All @@ -22,6 +23,12 @@
# Blender imports
import bpy
import blf
import bgl
import gpu

from gpu_extras.batch import batch_for_shader


from bpy.types import Operator
from mathutils import Matrix
from bpy_extras import view3d_utils
Expand All @@ -38,24 +45,49 @@ def draw_callback_px(self, context):
y = context.region.height
dims = blf.dimensions(0, 'A')

blf.position(font_id, 10, y - 20 - dims[1], 0)
#blf.position(font_id, 10, y - 20 - dims[1], 0)
blf.position(font_id, 10, 20 + dims[1], 0)

blf.size(font_id, 20, 72)

if context.area.x == self.area_align.x:
blf.draw(font_id, "Align: "+ self.align_msg)
points = [self.obj_align.matrix_world * p for p in self.align_points]
points = [self.obj_align.matrix_world @ p for p in self.align_points]
color = (1,0,0,1)
else:
blf.draw(font_id, "Base: " + self.base_msg)
points = [self.obj_align.matrix_world * p for p in self.base_points]
points = [self.obj_align.matrix_world @ p for p in self.base_points]
color = (0,1,0,1)

draw_3d_points_revised(context, points, color, 4)
#draw_3d_points_revised(context, points, color, 4)

for i, vec in enumerate(points):
ind = str(i)
draw_3d_text(context, font_id, ind, vec)


def draw_callback_view(self, context):
bgl.glPointSize(8)
#print('draw view!')
if context.area.x == self.area_align.x:
if not self.align_shader:
return

self.align_shader.bind()
self.align_shader.uniform_float("color", (1,0,1,1))
self.align_batch.draw(self.align_shader)
else:
if not self.base_shader:
return
self.base_shader.bind()
self.base_shader.uniform_float("color", (1,1,0,1))
self.base_batch.draw(self.base_shader)

bgl.glPointSize(1)
pass



class OBJECT_OT_align_pick_points(Operator):
"""Align two objects with 3 or more pair of picked points"""
bl_idname = "object.align_picked_points"
Expand Down Expand Up @@ -120,14 +152,15 @@ def modal(self, context, event):

view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
ray_target = ray_origin + (view_vector * ray_max)
ray_target = ray_origin + (ray_max * view_vector)

print('in the align object window')
(d, (ok,hit, normal, face_index)) = ray_cast_region2d(region, rv3d, coord, self.obj_align)
if hit:
print('hit! align_obj %s' % self.obj_align.name)
#local space of align object
self.align_points.append(hit)
self.create_batch_align()

else:

Expand All @@ -141,24 +174,26 @@ def modal(self, context, event):
coord = (event.mouse_x - region.x, event.mouse_y - region.y)
view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord)
ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord)
ray_target = ray_origin + (view_vector * ray_max)
ray_target = ray_origin + (ray_max * view_vector)

print('in the base object window')
(d, (ok,hit, normal, face_index)) = ray_cast_region2d(region, rv3d, coord, self.obj_base)
if ok:
print('hit! base_obj %s' % self.obj_base.name)
#points in local space of align object
self.base_points.append(self.obj_align.matrix_world.inverted() * self.obj_base.matrix_world * hit)

self.base_points.append(self.obj_align.matrix_world.inverted() @ self.obj_base.matrix_world @ hit)
self.create_batch_base()

return {'RUNNING_MODAL'}

elif event.type == 'RIGHTMOUSE' and event.value == 'PRESS':

if event.mouse_x > self.area_align.x and event.mouse_x < self.area_align.x + self.area_align.width:
self.align_points.pop()
self.create_batch_align()
else:
self.base_points.pop()
self.create_batch_base()

return {'RUNNING_MODAL'}

Expand Down Expand Up @@ -201,18 +236,20 @@ def modal(self, context, event):
return {'PASS_THROUGH'}

elif event.type in {'ESC'}:
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._2Dhandle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._3Dhandle, 'WINDOW')
return {'CANCELLED'}

elif event.type == 'RET':

if len(self.align_points) >= 3 and len(self.base_points) >= 3 and len(self.align_points) == len(self.base_points):
bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._2Dhandle, 'WINDOW')
bpy.types.SpaceView3D.draw_handler_remove(self._3Dhandle, 'WINDOW')
self.de_localize(context)
self.align_obj(context)

context.scene.objects.active = self.obj_align
self.obj_align.select = True
context.view_layer.objects.active = self.obj_align
self.obj_align.select_set(True)
self.obj_base = True

return {'FINISHED'}
Expand All @@ -238,9 +275,9 @@ def invoke(self, context, event):
obj2_name = [obj for obj in context.selected_objects if obj != context.object][0].name

for ob in context.scene.objects:
ob.select = False
ob.select_set(False)

context.scene.objects.active = None
bpy.context.view_layer.objects.active= None#context.scene.objects.active = None

#I did this stupid method becuase I was unsure
#if some things were being "sticky" and not
Expand All @@ -249,7 +286,7 @@ def invoke(self, context, event):
obj2 = bpy.data.objects[obj2_name]

for ob in bpy.data.objects:
if ob.select:
if ob.select_set(True):
print(ob.name)

screen = context.window.screen
Expand All @@ -258,31 +295,43 @@ def invoke(self, context, event):
if area.type == 'VIEW_3D':
break

bpy.ops.view3d.toolshelf() #close the first toolshelf
#bpy.ops.view3d.toolshelf() #close the first toolshelf
override = context.copy()
override['area'] = area

self.area_align = area

bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.5, mouse_x=-100, mouse_y=-100)
bpy.ops.screen.area_split(direction='VERTICAL', factor=0.5, cursor=(100,-100))#bpy.ops.screen.area_split(override, direction='VERTICAL', factor=0.5, mouse_x=-100, mouse_y=-100)
#bpy.ops.view3d.toolshelf() #close the 2nd toolshelf


context.scene.objects.active = obj1
obj1.select = True
obj2.select = False
bpy.context.view_layer.objects.active = obj1
obj1.select_set(True)
obj2.select_set(False)

bpy.ops.view3d.localview(override)


#..........Hide sidebar after area split...........................
for A in bpy.context.screen.areas:
if A.type == 'VIEW_3D' :
ctx = bpy.context.copy()
ctx['area'] = A
bpy.ops.screen.region_toggle(ctx, region_type='UI')
#...................................................................



obj1.select = False
context.scene.objects.active = None
obj1.select_set(False)
bpy.context.view_layer.objects.active = None
override = context.copy()
for area in screen.areas:
if area.as_pointer() not in areas:
override['area'] = area
self.area_base = area
bpy.ops.object.select_all(action = 'DESELECT')
context.scene.objects.active = obj2
obj2.select = True
bpy.context.view_layer.objects.active = obj2
obj2.select_set(True)
override['selected_objects'] = [obj2]
override['selected_editable_objects'] = [obj2]
override['object'] = obj2
Expand All @@ -298,13 +347,34 @@ def invoke(self, context, event):
self.align_points = []
self.base_points = []

self.base_batch = None
self.base_shader = None
self.align_batch = None
self.align_shader = None
context.window_manager.modal_handler_add(self)
self._handle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
self._2Dhandle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
self._3Dhandle = bpy.types.SpaceView3D.draw_handler_add(draw_callback_view, (self, context), 'WINDOW', 'POST_VIEW')


return {'RUNNING_MODAL'}

#############################################
# class methods


def create_batch_base(self):
verts = [self.obj_align.matrix_world @ p for p in self.base_points]
vertices = [(v.x, v.y, v.z) for v in verts]
self.base_shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
self.base_batch = batch_for_shader(self.base_shader, 'POINTS', {"pos":vertices})


def create_batch_align(self):
verts = [self.obj_align.matrix_world @ p for p in self.align_points]
vertices = [(v.x, v.y, v.z) for v in verts]
self.align_shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
self.align_batch = batch_for_shader(self.base_shader, 'POINTS', {"pos":vertices})

def de_localize(self,context):

override = context.copy()
Expand All @@ -316,10 +386,15 @@ def de_localize(self,context):
bpy.ops.view3d.localview(override)
bpy.ops.view3d.view_selected(override)

#Crash Blender?
bpy.ops.screen.area_join(min_x=self.area_align.x,min_y=self.area_align.y, max_x=self.area_base.x, max_y=self.area_base.y)
bpy.ops.view3d.toolshelf()
#............Crash Blender? Resolve................................
xj = int(self.area_align.width + 1)
yj = int(self.area_align.y + self.area_align.height / 2)
bpy.ops.screen.area_join(cursor=(xj,yj))
#..................................................................
#bpy.ops.view3d.toolshelf()

bpy.ops.screen.screen_full_area()
bpy.ops.screen.screen_full_area()
#ret = bpy.ops.screen.area_join(min_x=area_base.x,min_y=area_base.y, max_x=area_align.x, max_y=area_align.y)

def align_obj(self,context):
Expand Down Expand Up @@ -361,7 +436,7 @@ def align_obj(self,context):

#because we calced transform in local space
#it's this easy to update the obj...
self.obj_align.matrix_world = self.obj_align.matrix_world * new_mat
self.obj_align.matrix_world = self.obj_align.matrix_world @ new_mat

self.obj_align.update_tag()
context.scene.update()
context.view_layer.update()
Loading