#!BPY """ Registration info for Blender menus: <- these words are ignored Name: 'Click project from face' Blender: 242 Group: 'UVCalculation' Tooltip: '3 Clicks to project uvs onto selected faces.' """ __author__ = ["Campbell Barton"] __url__ = ("blender", "elysiun", "http://members.iinet.net.au/~cpbarton/ideasman/") __version__ = "0.1" __bpydoc__=\ ''' http://mediawiki.blender.org/index.php/Scripts/Manual/UV_Calculate/Click_project_from_face " ''' # -------------------------------------------------------------------------- # Click project v0.1 by Campbell Barton (AKA Ideasman) # -------------------------------------------------------------------------- # ***** BEGIN GPL LICENSE BLOCK ***** # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # ***** END GPL LICENCE BLOCK ***** # -------------------------------------------------------------------------- import Blender import BPyMesh import BPyWindow mouseViewRay= BPyWindow.mouseViewRay from Blender import Mathutils, Window, Scene, Draw, sys from Blender.Mathutils import CrossVecs, Vector, Matrix, LineIntersect, Intersect #, AngleBetweenVecs, Intersect LMB= Window.MButs['L'] RMB= Window.MButs['R'] def using_modifier(ob): for m in ob.modifiers: if m[Blender.Modifier.Settings.REALTIME]: return True return False def mouseup(): # Loop until click mouse_buttons = Window.GetMouseButtons() while not mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() while mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() def mousedown_wait(): # If the menu has just been pressed dont use its mousedown, mouse_buttons = Window.GetMouseButtons() while mouse_buttons & LMB: mouse_buttons = Window.GetMouseButtons() sys.sleep(10) def main(): scn = Scene.GetCurrent() ob = scn.objects.active if not ob or ob.type!='Mesh': return mousedown_wait() # so the menu items clicking dosnt trigger the mouseclick Window.DrawProgressBar (0.0, '') Window.DrawProgressBar (0.1, '(1 of 3) Click on a face corner') # wait for a click mouse_buttons = Window.GetMouseButtons() while not mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() # Allow for RMB cancel if mouse_buttons & RMB: return while mouse_buttons & LMB: sys.sleep(10) mouse_buttons = Window.GetMouseButtons() Window.DrawProgressBar (0.2, '(2 of 3 ) Click confirms the U coords') mousedown_wait() obmat= ob.matrixWorld screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) if not mouseInView or not OriginA: return me = ob.getData(mesh=1) # Get the face under the mouse face_click, isect, side = BPyMesh.pickMeshRayFace(me, OriginA, DirectionA) if not face_click: return proj_z_component = face_click.no if not face_click: return # Find the face vertex thats closest to the mouse, # this vert will be used as the corner to map from. best_v= None best_length = 10000000 vi1 = None for i, v in enumerate(face_click.v): l = (v.co-isect).length if l < best_length: best_v = v best_length = l vi1 = i # now get the 2 edges in the face that connect to v # we can work it out fairly easerly if len(face_click)==4: if vi1==0: vi2, vi3= 3,1 elif vi1==1: vi2, vi3= 0,2 elif vi1==2: vi2, vi3= 1,3 elif vi1==3: vi2, vi3= 2,0 else: if vi1==0: vi2, vi3= 2,1 elif vi1==1: vi2, vi3= 0,2 elif vi1==2: vi2, vi3= 1,0 face_corner_main =face_click.v[vi1].co face_corner_a =face_click.v[vi2].co face_corner_b =face_click.v[vi3].co line_a_len = (face_corner_a-face_corner_main).length line_b_len = (face_corner_b-face_corner_main).length orig_cursor = Window.GetCursorPos() Window.SetCursorPos(face_corner_main.x, face_corner_main.y, face_corner_main.z) SHIFT = Window.Qual.SHIFT MODE = 0 # firstclick, 1, secondclick mouse_buttons = Window.GetMouseButtons() project_mat = Matrix([0,0,0], [0,0,0], [0,0,0]) def get_face_coords(f): f_uv = f.uv return [(v.co-face_corner_main, f_uv[i]) for i,v in enumerate(f.v)] SELECT_FLAG = Blender.Mesh.FaceFlags.SELECT HIDE_FLAG = Blender.Mesh.FaceFlags.HIDE def use_face(f_flag): if f_flag & HIDE_FLAG: return False elif f_flag & SELECT_FLAG: return True else: return False coords = [ (co,uv) for f in me.faces if use_face(f.flag) for co, uv in get_face_coords(f)] coords_orig = [uv.copy() for co, uv in coords] USE_MODIFIER = using_modifier(ob) while 1: if mouse_buttons & LMB: if MODE == 0: mousedown_wait() Window.DrawProgressBar (0.8, '(3 of 3 ) Click confirms the V coords') MODE = 1 # second click # Se we cont continually set the length and get float error proj_y_component_orig = proj_y_component.copy() else: break elif mouse_buttons & RMB: # Restore old uvs for i, uv_orig in enumerate(coords_orig): coords[i][1][:] = uv_orig break mouse_buttons = Window.GetMouseButtons() screen_x, screen_y = Window.GetMouseCoords() mouseInView, OriginA, DirectionA = mouseViewRay(screen_x, screen_y, obmat) if not mouseInView: continue # Do a ray tri intersection, not clipped by the tri new_isect = Intersect(face_corner_main, face_corner_a, face_corner_b, DirectionA, OriginA, False) new_isect_alt = new_isect + DirectionA*0.0001 # The distance from the mouse cursor ray vector to the edge line_isect_a_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_a) line_isect_b_pair = LineIntersect(new_isect, new_isect_alt, face_corner_main, face_corner_b) # SHIFT to flip the axis. is_shift = Window.GetKeyQualifiers() & SHIFT if MODE == 0: line_dist_a = (line_isect_a_pair[0]-line_isect_a_pair[1]).length line_dist_b = (line_isect_b_pair[0]-line_isect_b_pair[1]).length if line_dist_a < line_dist_b: proj_x_component = face_corner_a - face_corner_main y_axis_length = line_b_len x_axis_length = (line_isect_a_pair[1]-face_corner_main).length else: proj_x_component = face_corner_b - face_corner_main y_axis_length = line_a_len x_axis_length = (line_isect_b_pair[1]-face_corner_main).length proj_y_component = CrossVecs(proj_x_component, proj_z_component) proj_y_component.length = 1/y_axis_length proj_x_component.length = 1/x_axis_length if is_shift: proj_x_component.negate() else: proj_y_component[:] = proj_y_component_orig if line_dist_a < line_dist_b: proj_y_component.length = 1/(line_isect_a_pair[1]-new_isect).length else: proj_y_component.length = 1/(line_isect_b_pair[1]-new_isect).length if is_shift: proj_y_component.negate() # Use the existing matrix to make a new 3x3 projecton matrix project_mat[0][:] = -proj_y_component project_mat[1][:] = -proj_x_component project_mat[2][:] = proj_z_component # Apply the projection matrix for proj_co, uv in coords: uv[:] = (project_mat * proj_co)[0:2] if USE_MODIFIER: me.update() Window.Redraw(Window.Types.VIEW3D) Window.SetCursorPos(*orig_cursor) Window.RedrawAll() if __name__=='__main__': main() Window.DrawProgressBar(1.0, '')