* UI tweaks to python controller (more space for module name), setParent actuator use less space
* object_drop.py - option to orient to face normal (useful for scattering objects over terrain), accounts for normal flipping and can adjust the orientation %.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
#!BPY
|
||||
"""
|
||||
Name: 'Drop Onto Ground'
|
||||
Blender: 245
|
||||
Blender: 249
|
||||
Group: 'Object'
|
||||
Tooltip: 'Drop the selected objects onto "ground" objects'
|
||||
"""
|
||||
__author__= "Campbell Barton"
|
||||
__url__= ["blender.org", "blenderartists.org"]
|
||||
__version__= "1.0"
|
||||
__version__= "1.1"
|
||||
|
||||
__bpydoc__= """
|
||||
"""
|
||||
@@ -36,6 +36,7 @@ __bpydoc__= """
|
||||
|
||||
|
||||
from Blender import Draw, Geometry, Mathutils, Window
|
||||
from Blender.Mathutils import Vector, AngleBetweenVecs, RotationMatrix
|
||||
import bpy
|
||||
|
||||
|
||||
@@ -44,6 +45,8 @@ GLOBALS['GROUND_SOURCE'] = [Draw.Create(1), Draw.Create(0)]
|
||||
GLOBALS['GROUND_GROUP_NAME'] = Draw.Create('terrain')
|
||||
GLOBALS['DROP_AXIS'] = [Draw.Create(1), Draw.Create(0)] # on what axis will we drop?
|
||||
GLOBALS['DROP_OVERLAP_CHECK'] = Draw.Create(1) # is the terrain a single skin?
|
||||
GLOBALS['DROP_ORIENT'] = Draw.Create(1)
|
||||
GLOBALS['DROP_ORIENT_VALUE'] = Draw.Create(100.0)
|
||||
GLOBALS['EVENT'] = 2
|
||||
GLOBALS['MOUSE'] = None
|
||||
|
||||
@@ -52,19 +55,18 @@ def collect_terrain_triangles(obs_terrain):
|
||||
me = bpy.data.meshes.new()
|
||||
|
||||
for ob in obs_terrain:
|
||||
# this matrix takes the object and drop matrix into account
|
||||
ob_mat = ob.matrixWorld # * drop_matrix
|
||||
|
||||
def blend_face_to_terrain_tris(f):
|
||||
cos = [v.co*ob_mat for v in f]
|
||||
if len(cos) == 4: return [(cos[0], cos[1], cos[2]), (cos[0], cos[2], cos[3])]
|
||||
else: return [(cos[0], cos[1], cos[2]), ]
|
||||
no = f.no
|
||||
cos = [v.co for v in f]
|
||||
if len(cos) == 4: return [(cos[0], cos[1], cos[2], no), (cos[0], cos[2], cos[3], no)]
|
||||
else: return [(cos[0], cos[1], cos[2], no), ]
|
||||
|
||||
# Clear
|
||||
me.verts = None
|
||||
try: me.getFromObject(ob)
|
||||
except: pass
|
||||
|
||||
me.transform(ob.matrixWorld)
|
||||
for f in me.faces: # may be [], thats ok
|
||||
terrain_tris.extend( blend_face_to_terrain_tris(f) )
|
||||
|
||||
@@ -72,30 +74,34 @@ def collect_terrain_triangles(obs_terrain):
|
||||
return terrain_tris
|
||||
|
||||
def calc_drop_loc(ob, terrain_tris, axis):
|
||||
pt = Mathutils.Vector(ob.loc)
|
||||
pt = Vector(ob.loc)
|
||||
|
||||
isect = None
|
||||
isect_best = None
|
||||
isect_best_no = None
|
||||
isect_best_len = 0.0
|
||||
|
||||
for t1,t2,t3 in terrain_tris:
|
||||
for t1,t2,t3, no in terrain_tris:
|
||||
#if Geometry.PointInTriangle2D(pt, t1,t2,t3):
|
||||
isect = Mathutils.Intersect(t1, t2, t3, axis, pt, 1) # 1==clip
|
||||
if isect:
|
||||
if not GLOBALS['DROP_OVERLAP_CHECK'].val:
|
||||
# Find the first location
|
||||
return isect
|
||||
return isect, no
|
||||
else:
|
||||
if isect_best:
|
||||
isect_len = (pt-isect).length
|
||||
if isect_len < isect_best_len:
|
||||
isect_best_len = isect_len
|
||||
isect_best = isect
|
||||
isect_best_no = no
|
||||
|
||||
else:
|
||||
isect_best_len = (pt-isect).length
|
||||
isect_best = isect;
|
||||
return isect_best
|
||||
isect_best_no = no
|
||||
|
||||
return isect_best, isect_best_no
|
||||
|
||||
|
||||
def error_nogroup():
|
||||
@@ -135,13 +141,28 @@ def terrain_clamp(event, value):
|
||||
|
||||
|
||||
if GLOBALS['DROP_AXIS'][0].val:
|
||||
axis = Mathutils.Vector(0,0,-1)
|
||||
axis = Vector(0,0,-1)
|
||||
else:
|
||||
axis = Mathutils.Vector(Window.GetViewVector())
|
||||
axis = Vector(Window.GetViewVector())
|
||||
|
||||
do_orient = GLOBALS['DROP_ORIENT'].val
|
||||
do_orient_val = GLOBALS['DROP_ORIENT_VALUE'].val/100.0
|
||||
if not do_orient_val: do_orient = False
|
||||
|
||||
for ob in obs_clamp:
|
||||
loc = calc_drop_loc(ob, terrain_tris, axis)
|
||||
loc, no = calc_drop_loc(ob, terrain_tris, axis)
|
||||
if loc:
|
||||
if do_orient:
|
||||
try: ang = AngleBetweenVecs(no, axis)
|
||||
except:ang = 0.0
|
||||
if ang > 90.0:
|
||||
no = -no
|
||||
ang = 180.0-ang
|
||||
|
||||
if ang > 0.0001:
|
||||
ob_matrix = ob.matrixWorld * RotationMatrix(ang * do_orient_val, 4, 'r', axis.cross(no))
|
||||
ob.setMatrix(ob_matrix)
|
||||
|
||||
ob.loc = loc
|
||||
|
||||
# to make the while loop exist
|
||||
@@ -175,7 +196,8 @@ def do_ground_group_name(e,v):
|
||||
if not g: error_nogroup()
|
||||
GLOBALS['EVENT'] = e
|
||||
|
||||
|
||||
def do_dummy(e,v):
|
||||
GLOBALS['EVENT'] = e
|
||||
|
||||
EVENT_NONE = 0
|
||||
EVENT_EXIT = 1
|
||||
@@ -185,7 +207,7 @@ def terain_clamp_ui():
|
||||
# Only to center the UI
|
||||
x,y = GLOBALS['MOUSE']
|
||||
x-=40
|
||||
y-=60
|
||||
y-=70
|
||||
|
||||
Draw.Label('Drop Axis', x-70,y+120, 60, 20)
|
||||
Draw.BeginAlign()
|
||||
@@ -204,7 +226,13 @@ def terain_clamp_ui():
|
||||
|
||||
GLOBALS['DROP_OVERLAP_CHECK'] = Draw.Toggle('Overlapping Terrain', EVENT_NONE, x-70, y+20, 190, 20, GLOBALS['DROP_OVERLAP_CHECK'].val, "Check all terrain triangles and use the top most (slow)")
|
||||
|
||||
Draw.PushButton('Drop Objects', EVENT_EXIT, x+20, y-10, 100, 20, 'Drop the selected objects', terrain_clamp)
|
||||
Draw.BeginAlign()
|
||||
GLOBALS['DROP_ORIENT'] = Draw.Toggle('Orient Normal', EVENT_REDRAW, x-70, y-10, 110, 20, GLOBALS['DROP_ORIENT'].val, "Rotate objects to the face normal", do_dummy)
|
||||
if GLOBALS['DROP_ORIENT'].val:
|
||||
GLOBALS['DROP_ORIENT_VALUE'] = Draw.Number('', EVENT_NONE, x+40, y-10, 80, 20, GLOBALS['DROP_ORIENT_VALUE'].val, 0.0, 100.0, "Percentage to orient 0.0 - 100.0")
|
||||
Draw.EndAlign()
|
||||
|
||||
Draw.PushButton('Drop Objects', EVENT_EXIT, x+20, y-40, 100, 20, 'Drop the selected objects', terrain_clamp)
|
||||
|
||||
# So moving the mouse outside the popup exits the while loop
|
||||
GLOBALS['EVENT'] = EVENT_EXIT
|
||||
|
||||
@@ -1603,12 +1603,12 @@ static short draw_controllerbuttons(bController *cont, uiBlock *block, short xco
|
||||
|
||||
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButI(block, MENU, B_REDR, "Execution Method%t|Script%x0|Module%x1", xco+24,yco-24, 66, 19, &pc->mode, 0, 0, 0, 0, "Python script type (textblock or module - faster)");
|
||||
uiDefButI(block, MENU, B_REDR, "Execution Method%t|Script%x0|Module%x1", xco+4,yco-23, 66, 19, &pc->mode, 0, 0, 0, 0, "Python script type (textblock or module - faster)");
|
||||
if(pc->mode==0)
|
||||
uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "", xco+90,yco-24,width-90, 19, &pc->text, "Blender textblock to run as a script");
|
||||
uiDefIDPoinBut(block, test_scriptpoin_but, ID_SCRIPT, 1, "", xco+70,yco-23,width-74, 19, &pc->text, "Blender textblock to run as a script");
|
||||
else {
|
||||
uiDefBut(block, TEX, 1, "", xco+90,yco-24,(width-90)-25, 19, pc->module, 0, 63, 0, 0, "Module name and function to run e.g. \"someModule.main\". Internal texts and external python files can be used");
|
||||
uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-24, 19, 19, &pc->flag, 0, 0, 0, 0, "Continuously reload the module from disk for editing external modules without restarting");
|
||||
uiDefBut(block, TEX, 1, "", xco+70,yco-23,(width-70)-25, 19, pc->module, 0, 63, 0, 0, "Module name and function to run e.g. \"someModule.main\". Internal texts and external python files can be used");
|
||||
uiDefButBitI(block, TOG, CONT_PY_DEBUG, B_REDR, "D", (xco+width)-25, yco-23, 19, 19, &pc->flag, 0, 0, 0, 0, "Continuously reload the module from disk for editing external modules without restarting");
|
||||
}
|
||||
uiBlockEndAlign(block);
|
||||
|
||||
@@ -2748,19 +2748,19 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
|
||||
|
||||
if(parAct->type==ACT_PARENT_SET) {
|
||||
|
||||
ysize= 68;
|
||||
ysize= 48;
|
||||
glRects(xco, yco-ysize, xco+width, yco);
|
||||
uiEmboss((float)xco, (float)yco-ysize, (float)xco+width, (float)yco, 1);
|
||||
uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+40, yco-44, (width-80), 19, &(parAct->ob), "Set this object as parent");
|
||||
uiDefIDPoinBut(block, test_obpoin_but, ID_OB, 1, "OB:", xco+95, yco-24, (width-100), 19, &(parAct->ob), "Set this object as parent");
|
||||
uiBlockBeginAlign(block);
|
||||
uiDefButBitS(block, TOGN, ACT_PARENT_COMPOUND, B_REDR,
|
||||
"Compound",
|
||||
xco + 40, yco - 64, (width - 80)/2, 19, &parAct->flag,
|
||||
xco + 5, yco - 44, (width - 10)/2, 19, &parAct->flag,
|
||||
0.0, 0.0, 0, 0,
|
||||
"Add this object shape to the parent shape (only if the parent shape is already compound)");
|
||||
uiDefButBitS(block, TOGN, ACT_PARENT_GHOST, B_REDR,
|
||||
"Ghost",
|
||||
xco + 40 + ((width - 80)/2), yco - 64, (width - 80)/2, 19, &parAct->flag,
|
||||
xco + 5 + ((width - 10)/2), yco - 44, (width - 10)/2, 19, &parAct->flag,
|
||||
0.0, 0.0, 0, 0,
|
||||
"Make this object ghost while parented (only if not compound)");
|
||||
uiBlockEndAlign(block);
|
||||
@@ -2773,7 +2773,7 @@ static short draw_actuatorbuttons(Object *ob, bActuator *act, uiBlock *block, sh
|
||||
}
|
||||
|
||||
str= "Parent %t|Set Parent %x0|Remove Parent %x1";
|
||||
uiDefButI(block, MENU, B_REDR, str, xco+40, yco-24, (width-80), 19, &parAct->type, 0.0, 0.0, 0, 0, "");
|
||||
uiDefButI(block, MENU, B_REDR, str, xco+5, yco-24, parAct->type==1?(width-80):90, 19, &parAct->type, 0.0, 0.0, 0, 0, "");
|
||||
|
||||
yco-= ysize;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user