import poser, Numeric, math, time from Tkinter import * FLT_EPSILON = 1.19209290e-07 scene = poser.Scene() """ """ plane_name = "SKINNERPLANE" box_name = "MR. SKINNER BOX" def start(): global box_name, skinnerbox skinnerbox = testing_boxes([0.0,0.25,0.0],0.25,"MR. SKINNER BOX",2,0) scene.SelectActor(skinnerbox) box_name = skinnerbox.InternalName() set_up_callback(skinnerbox) def run(thickness=0.002,divs=30,ring=10,smooth=0,inflate=0): global plane_name box = b_box_ock(vertexPos(skinnerbox.Geometry(),worldspace=0)) cdistz = distance3d([box[0],box[2],box[4]],[box[0],box[2],box[5]]) # Z axis cdistx = distance3d([box[0],box[2],box[4]],[box[1],box[2],box[4]]) # X axis cdisty = distance3d([box[0],box[2],box[4]],[box[0],box[3],box[4]]) # Y axis ring_height = cdisty/ring plane = build_plane("SKINNERPLANE",display=1) plane_name = plane.InternalName() plane.SetOrigin(0.0,0.25,0.0) plane.SetEndPoint(0.0,0.50,0.0) plane.ParameterByCode(poser.kParmCodeXTRAN).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeXTRAN).Value()) plane.ParameterByCode(poser.kParmCodeYTRAN).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeYTRAN).Value()) plane.ParameterByCode(poser.kParmCodeZTRAN).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeZTRAN).Value()) plane.ParameterByCode(poser.kParmCodeXROT).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeXROT).Value()) plane.ParameterByCode(poser.kParmCodeYROT).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeYROT).Value()) plane.ParameterByCode(poser.kParmCodeZROT).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeZROT).Value()) plane.ParameterByCode(poser.kParmCodeASCALE).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeASCALE).Value()) plane.ParameterByCode(poser.kParmCodeXSCALE).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeXSCALE).Value()) plane.ParameterByCode(poser.kParmCodeYSCALE).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeYSCALE).Value()) plane.ParameterByCode(poser.kParmCodeZSCALE).SetValue(skinnerbox.ParameterByCode(poser.kParmCodeZSCALE).Value()) ring_height *= skinnerbox.ParameterByCode(poser.kParmCodeASCALE).Value() ring_height *= skinnerbox.ParameterByCode(poser.kParmCodeYSCALE).Value() newskin = make_skin(plane,ring_height,thickness=thickness,ring=ring+1,divs=divs,smooth=smooth,inflate=inflate) if newskin: # Set the new loop's origin, endpoint, and orientation to match those of the plane. (Requested by lesbentley.) boxmat = skinnerbox.WorldMatrix() origin = skinnerbox.Origin() endpoint = skinnerbox.EndPoint() origin = point_by_matrix(origin,boxmat) endpoint = point_by_matrix(endpoint,boxmat) orientation = [0.0,0.0,0.0] # New loop's orientation will be X,Y,Z rotations of plane. orientation[0] = skinnerbox.ParameterByCode(poser.kParmCodeXROT).Value() orientation[1] = skinnerbox.ParameterByCode(poser.kParmCodeYROT).Value() orientation[2] = skinnerbox.ParameterByCode(poser.kParmCodeZROT).Value() skinact = scene.ActorByInternalName(newskin) skinact.SetOrigin(origin[0],origin[1],origin[2]) skinact.SetEndPoint(endpoint[0],endpoint[1],endpoint[2]) skinact.SetOrientation(orientation[0],orientation[1],orientation[2]) scene.SelectActor(skinnerbox) scene.DeleteCurrentProp() scene.SelectActor(plane) scene.DeleteCurrentProp() scene.SelectActor(skinact) scene.DrawAll() else: scene.SelectActor(skinnerbox) scene.DeleteCurrentProp() scene.SelectActor(plane) scene.DeleteCurrentProp() scene.DrawAll() def set_up_callback(skinnerbox): """Set up the plane prop dials, for use with the callback function.""" endst = "END SCRIPT - Use dial!" runst = "RUN SCRIPT - Use dial!" thk = "Offset" rng = "Rows" div = "Columns" smo = "Apply smoothing" inf = "Create 'Expand' morph" skinnerbox.CreateValueParameter(endst) skinnerbox.CreateValueParameter(runst) skinnerbox.CreateValueParameter(smo) skinnerbox.CreateValueParameter(inf) skinnerbox.CreateValueParameter(thk) skinnerbox.CreateValueParameter(rng) skinnerbox.CreateValueParameter(div) runparm = skinnerbox.Parameter(runst) endparm = skinnerbox.Parameter(endst) thkparm = skinnerbox.Parameter(thk) rngparm = skinnerbox.Parameter(rng) divparm = skinnerbox.Parameter(div) smoparm = skinnerbox.Parameter(smo) infparm = skinnerbox.Parameter(inf) runparm.SetValue(0.0) endparm.SetValue(0.0) thkparm.SetValue(0.005) rngparm.SetValue(20) divparm.SetValue(30) smoparm.SetValue(0.0) infparm.SetValue(0.0) runparm.SetSensitivity(1.0) endparm.SetSensitivity(1.0) rngparm.SetSensitivity(1.0) divparm.SetSensitivity(1.0) smoparm.SetSensitivity(1.0) infparm.SetSensitivity(1.0) thkparm.SetSensitivity(0.001) scene.SetEventCallback(eventCB) def eventCB(scn,event): """Scene event callback function.""" global box_name, skinnerbox if( (event & poser.kEventCodePARMCHANGED) != 0): runparm = skinnerbox.Parameter("RUN SCRIPT - Use dial!") if runparm.Value() != 0.0: scene.ClearEventCallback() ring = abs(int(skinnerbox.Parameter("Rows").Value())) if ring <= 0: ring = 10 divs = abs(int(skinnerbox.Parameter("Columns").Value())) if divs <= 3: divs = 30 thickness = skinnerbox.Parameter("Offset").Value() smooth = skinnerbox.Parameter("Apply smoothing").Value() if smooth > 0.0: smooth = 1 else: smooth = 0 inflate = skinnerbox.Parameter("Create 'Expand' morph").Value() if inflate > 0.0: inflate = 1 else: inflate = 0 run(thickness=thickness,divs=divs,ring=ring,smooth=smooth,inflate=inflate) return endparm = skinnerbox.Parameter("END SCRIPT - Use dial!") if endparm.Value() != 0.0: scene.ClearEventCallback() scene.DeleteCurrentProp() return if ( (event & poser.kEventCodeACTORDELETED) != 0): acts = [a.InternalName() for a in scene.Actors()] if not box_name in acts: scene.ClearEventCallback() def get_actverts(): """Screen actor selections to be tested against plane, log vertexPos array for each selected actor""" acts_dict = {} for a in scene.Actors(): if a.IsBodyPart() or a.IsProp(): if a.OnOff(): g = a.Geometry() if g: if a.InternalName() != plane_name and a.InternalName() != box_name and a.InternalName() != "GROUND": acts_dict[a.InternalName()] = vertexPos(g) return acts_dict def make_skin(plane,ring_height,thickness=0.002,ring=10,divs=30,smooth=0,inflate=0,exclude=""): """ bounding box format is [minX,maxX,minY,maxY,minZ,maxZ] This function finds vertices or edges which intersect the plane, then creates a 2D convex hull from these points. A deformed toroid shape is extruded around this ringed path. """ verts = [] goodrings = 0 basemesh = myMesh(plane,vertexPos(plane.Geometry(),worldspace=0)) # Get the mesh data for the un-transformed plane basemesh.get_norms() basenorm = basemesh.pnorms[0] baseplane = basemesh.pplanes[0] base_bbox = b_box_ock(basemesh.verts) bp_nx, bp_mx, bp_ny, bp_my, bp_nz, bp_mz = base_bbox actors = get_actverts() acts = actors.keys() sbox = [-0.25,0.25,0.0,0.5,-0.25,0.25] actors = get_actverts() abox = [100000.0,-100000.0,100000.0,-100000.0,100000.0,-100000.0] planemat = plane.WorldMatrix() # Get the world matrix and its inverse for the plane invplanemat = matrix_invert(planemat) for i in range(len(acts)): verts = [] for j in actors[acts[i]]: verts.append(point_by_matrix(j,invplanemat)) inbox = in_box(sbox,verts) if inbox.count(1): verts = [[k for k in verts[j]] for j in range(len(verts)) if inbox[j] == 1] abox = mix_boxes(abox,b_box_ock(verts)) else: del actors[acts[i]] abox = increase_box(abox,-FLT_EPSILON) # Shrink merged AABB by tiny amount, to fake out the AABB-plane intersect code, so it will recognize minY value ascale = skinnerbox.ParameterByCode(poser.kParmCodeASCALE).Value() # Need to scale the min and max Y values yscale = skinnerbox.ParameterByCode(poser.kParmCodeYSCALE).Value() minY = abox[2] *ascale * yscale maxY = abox[3] *ascale * yscale ring_height = (maxY-minY)/(ring-1) planemesh = myMesh(plane,vertexPos(plane.Geometry())) planemesh.get_norms() pnorm = planemesh.pnorms[0] verts = [] acts = actors.keys() for levelnum in range(ring): xtran = plane.ParameterByCode(poser.kParmCodeXTRAN) ytran = plane.ParameterByCode(poser.kParmCodeYTRAN) ztran = plane.ParameterByCode(poser.kParmCodeZTRAN) newpos = Numeric.array([xtran.Value(),ytran.Value(),ztran.Value()],Numeric.Float) if levelnum > 0: newpos += (pnorm*ring_height) xtran.SetValue(newpos[0]) ytran.SetValue(newpos[1]) ztran.SetValue(newpos[2]) else: newpos += (pnorm*minY) xtran.SetValue(newpos[0]) ytran.SetValue(newpos[1]) ztran.SetValue(newpos[2]) scene.DrawAll() planemesh = myMesh(plane,vertexPos(plane.Geometry())) planemesh.get_norms() boxplane = b_box_ock(planemesh.verts) plane_center = box_center(boxplane) # Get the center of the plane, for use in identifying center loop ring, below. pnorm = planemesh.pnorms[0] pplane = planemesh.pplanes[0] planemat = plane.WorldMatrix() # Get the world matrix and its inverse for the plane invplanemat = matrix_invert(planemat) meshes = [] for a in acts: if a == exclude: # Skip the excluded actor name continue abox = b_box_ock(actors[a]) intersect = AABB_plane_intersect(abox,pnorm,pplane) # Test actor AABB for intersection with plane if intersect == 0: # The actor's bounding box intersects the plane averts = box_verts(abox) mat_averts = [] # Get bounding box for actor, move to world origin for i in range(8): mat_avert = point_by_matrix(averts[i],invplanemat) #testing_boxes(mat_avert,0.002,"Transformed",0,1) mat_averts.append([j for j in mat_avert]) mat_abox = b_box_ock(mat_averts) if mat_abox[0] > bp_mx or mat_abox[1] < bp_nx: # Check transformed actor AABB against plane X,Z limits continue if mat_abox[2] > bp_my or mat_abox[3] < bp_ny: continue if mat_abox[4] > bp_mz or mat_abox[5] < bp_nz: continue meshes.append(myMesh(scene.ActorByInternalName(a),actors[a])) mesh = meshes[len(meshes)-1] mesh.matverts = [] for vi in range(len(mesh.verts)): point = point_by_matrix(mesh.verts[vi],invplanemat) # Transform actor vertices to world origin using inverse matrix of plane mesh.matverts.append([i for i in point]) #testing_boxes(point,0.002,"Transformed",0,1) mesh.matverts = Numeric.array(mesh.matverts,Numeric.Float) mesh.edgescreen = [[1 for j in i] for i in mesh.edges] for pi in range(mesh.geom.NumPolygons()): # Precompile a list of valid edges, to allow quick full-polygon skipping, below edges = mesh.edges[pi] for ei in range(len(edges)): edge = edges[ei] e0 = mesh.matverts[edge[0]] e1 = mesh.matverts[edge[1]] if (e0[1] > 0.0 and e1[1] > 0.0) or (e0[1] < 0.0 and e1[1] < 0.0): # Y coord for plane is now 0.0 mesh.edgescreen[pi][ei] = 0 # If both edge vertices are either above or below the plane, there's no intersection and we can skip this edge continue if (e0[0] < bp_nx and e1[0] < bp_nx) or (e0[0] > bp_mx and e1[0] > bp_mx): mesh.edgescreen[pi][ei] = 0 # Skip the edge if both points are out of range on X or Z continue if (e0[2] < bp_nz and e1[2] < bp_nz) or (e0[2] > bp_mz and e1[2] > bp_mz): mesh.edgescreen[pi][ei] = 0 continue if meshes == []: # No actors were found for this pass. continue hitpoints = [] for mesh in meshes: # Find vertices with edges which intersect the plane, for each actor for pi in range(mesh.geom.NumPolygons()): if not mesh.edgescreen[pi].count(1): # If none of the edges for the poly will intersect the plane properly, skip the entire polygon. continue edges = mesh.edges[pi] for ei in range(len(edges)): if not mesh.edgescreen[pi][ei]: # If the edge will not intersect the plane, skip it. continue edge = edges[ei] e0 = mesh.matverts[edge[0]] e1 = mesh.matverts[edge[1]] # Much of this next bit was copied directly from Spanki's ray-casting code for TDMT. Good stuff. d = e1 - e0 ndota = d[0] * basenorm[0] + d[1] * basenorm[1] + d[2] * basenorm[2] if ndota <= 0.0: # Just check the edges on one side of the plane continue ndotv = basenorm[0] * e0[0] + basenorm[1] * e0[1] + basenorm[2] * e0[2] isect = (baseplane - ndotv) / ndota testPoint = [e0[0] + (d[0] * isect), e0[1] + (d[1] * isect), e0[2] + (d[2] * isect)] if testPoint[0] < bp_nx or testPoint[0] > bp_mx or testPoint[2] < bp_nz or testPoint[2] > bp_mz: continue # If one vert of edge was in bounds, we'll have a hit, but the intersection may not be in bounds. hitpoints.append([i for i in testPoint]) #testing_boxes(testPoint,0.002,"Intersect",0,1) for mesh in meshes: mesh = None del meshes del planemesh if hitpoints == []: # No vertices found for this pass. continue else: goodrings += 1 # A ring of vertices was created, so add it to the total ring count hitpoints = [(i[0],i[2]) for i in hitpoints] hullpoints = hulls(hitpoints) # Get the 2D convex hull for our edge points #for i in hullpoints: #testing_boxes2d(i,0.002,"Hull",0,1) hullpoints = convexHull(hullpoints) # Sometimes the hull function fails and the path includes inner verts. Try to correct with a secondary hull. hull2 = [[] for i in hullpoints] for i in range(len(hullpoints)): # Switch back to 3D use here, to avoid ring-squashing effect in final geometry, due to scaling of original plane point = [hullpoints[i][0],0.0,hullpoints[i][1]] point = point_by_matrix(point,planemat) hull2[i] = [point[0],point[1],point[2]] hullpoints = Numeric.array(hull2,Numeric.Float) edges = [] edgelens = [] for i in range(len(hullpoints)): # Gather hull edge data up front to simplify subsequent looping if i == len(hullpoints)-1: j = 0 else: j = i + 1 edges.append([i,j]) dist = hullpoints[j] - hullpoints[i] dist = Numeric.sqrt( pow(dist[0],2) + pow(dist[1],2) + pow(dist[2],2) ) edgelens.append(dist) pathlen = path_length(hullpoints) # Distance around hull perimeter seglen = pathlen/divs # Length of a final ring segment hitpoints = [[0.0,0.0,0.0] for i in range(divs)] hitpoints = Numeric.array(hitpoints,Numeric.Float) for i in range(divs): # Get the proper locations for each evenly-spaced ring of the final loop by walking the perimeter of the hull total = 0.0 segdist = seglen * i for j in range(len(edges)): # Walk the perimeter, placing ring-markers as appropriate total += edgelens[j] if total >= segdist: hitdist = total-segdist dirx = hullpoints[edges[j][0]] - hullpoints[edges[j][1]] dirx = vector_normalize(dirx) point = hullpoints[edges[j][1]] + (dirx * hitdist) for j in range(3): hitpoints[i][j] = point[j] break edgelens = [] hullpoints = [] edges = [[] for i in hitpoints] # Pre-compile the hitpoints edges, to simplify the following for i in range(len(hitpoints)): if i == len(hitpoints)-1: j = 0 else: j = i + 1 edges[i] = [i,j] inner = -1 # Identify the inner ring for UV split vertical = pnorm # Having switched back to 3D use above, the relative "vertical" axis for use below is now the original normal of the plane. for i in range(len(hitpoints)): # Get the point locations for the ringed cross-sections point = hitpoints[i] e1 = edges[i] if i == 0: # We loop clockwise, so we need to use the neighboring edge in the counter-clockwise direction, to get the correct angles. e2 = edges[len(hitpoints)-1] else: e2 = edges[i-1] edge1 = hitpoints[e1[1]] - hitpoints[e1[0]] # Basically building a 2D vertex normal, here.... edge2 = hitpoints[e2[1]] - hitpoints[e2[0]] edge1 = vector_normalize(edge1) edge2 = vector_normalize(edge2) cross1 = vector_crossproduct(edge1,vertical) # Make two vertical planes cross2 = vector_crossproduct(edge2,vertical) cross1 = vector_normalize(cross1) # Plane normals are the crossproducts cross2 = vector_normalize(cross2) norm = (cross1 + cross2)/2 # Average and normalize norm = vector_normalize(norm) point = point + (norm * (thickness)) # Now that we have the 2D normal, inflate the loop by the thickness, to keep it from embedding verts.append([j for j in point]) edges = [] hitpoints = [] del actors ring = goodrings """ Now go on to build the new mesh.... """ verts = Numeric.array(verts,Numeric.Float) polys = Numeric.array([[i,4] for i in range(0,divs*(ring-1)*4,4)],Numeric.Int) sets = [] for i in range(ring-1): thisring = i*divs nextring = (i+1)*divs for j in range(divs): if j == 0: k = divs-1 else: k = j - 1 sets.append(thisring+j) sets.append(nextring+j) sets.append(nextring+k) sets.append(thisring+k) sets = Numeric.array(sets,Numeric.Int) # Get the UV data # --- UV's tiled by toroid ring --- inner = 0 tverts,tsets = ring_tile(ring-1,divs,inner,edgelens = []) tpolys = [[j for j in i] for i in polys] tverts = Numeric.array(tverts,Numeric.Float) tsets = Numeric.array(tsets,Numeric.Int) tpolys = Numeric.array(tpolys,Numeric.Int) # Create the new geometry newgeom = poser.NewGeometry() newgeom.AddGeneralMesh(polys,sets,verts,tpolys,tsets,tverts) # Make a prop from the geometry newprop = scene.CreatePropFromGeom(newgeom,"newskinnerprop") if not newprop: return "" scene.SelectActor(newprop) # Refresh the geometry by pulling a copy of it from the created prop newgeom = newprop.Geometry() # This is necessary to enable Poser 5 and 6 to add new materials to the geom. # Add a new material and set diffuse to white. newgeom.AddMaterialName("skinner_surface") for pi in range(len(polys)): p = newgeom.Polygon(pi) p.SetMaterialIndex(1) # First entry is always 'Preview'; second is the new material # Set the new geometry with added material for the prop newprop.SetGeometry(newgeom) # Set the prop's diffuse color for the new material newprop.Material("skinner_surface").SetDiffuseColor(1.0,1.0,1.0) # Set the material color # Optionally apply some smoothing to the mesh # Optionally add a "Fatness" morph to the loop if smooth or inflate: loopmesh = myMesh(newprop,vertexPos(newprop.Geometry())) # Gathering geometry data for the actor. See the myMesh class, below, and further use if smooth: # of the class, at the top of this function. loopmesh.vertneighbors(loopmesh.pverts) find_detail(loopmesh) loopmesh.polynorms(loopmesh.pverts) loopmesh.vertnorms_Geom() if smooth: smooth_mesh(loopmesh) if inflate: inflate_morph(loopmesh) del loopmesh return newprop.InternalName() def smooth_mesh(mesh): """Smooth the resulting loop""" for vi in range(mesh.geom.NumVertices()): vert = mesh.verts[vi] avg = Numeric.array([0.0,0.0,0.0],Numeric.Float) nbs = mesh.vneighbors[vi] for nbi in nbs: avg += mesh.verts[nbi] avg /= len(nbs) sub = mesh.verts[vi] - avg # 'Cheapie' volume preservation dist = Numeric.sqrt( pow(sub[0],2) + pow(sub[1],2) + pow(sub[2],2) ) distdiff = dist - mesh.dists[vi] avg += (mesh.vnorms[vi]*distdiff) avg = (vert + avg)/2 vert = mesh.geom.Vertex(vi) vert.SetX(avg[0]) vert.SetY(avg[1]) vert.SetZ(avg[2]) mesh.act.MarkGeomChanged() def inflate_morph(mesh): """ Add an optional "Fatness" morph to the loop. """ amt = 0.01 act = mesh.act act.SpawnTarget("Expand") morph = act.Parameter("Expand") for vi in range(mesh.geom.NumVertices()): vert = mesh.verts[vi] norm = mesh.vnorms[vi] delta = (vert + (norm * amt)) - vert morph.SetMorphTargetDelta(vi,delta[0],delta[1],delta[2]) def find_detail(mesh): """ Finds center (averaged position) of all neighbor vertices for each vertex. These are used for the 'cheapie' volume preservation applied by the smoothing """ mesh.detailverts = vertexPos(mesh.geom,worldspace=0) mesh.detail = [[0.0,0.0,0.0] for i in mesh.detailverts] mesh.dists = [0.0 for i in mesh.detailverts] for vi in range(len(mesh.detailverts)): nbs = mesh.vneighbors[vi] vert = mesh.detailverts[vi] avg = Numeric.array([0.0,0.0,0.0],Numeric.Float) for i in range(len(nbs)): nvi = nbs[i] nv = mesh.detailverts[nvi] for i in range(3): avg[i] += nv[i] for i in range(3): avg[i] /= len(nbs) mesh.detail[vi] = vert - avg sub = vert - avg mesh.dists[vi] = Numeric.sqrt( pow(sub[0],2) + pow(sub[1],2) + pow(sub[2],2) ) def ring_tile(divs,ring,inner,edgelens = []): """Tiled UV mapping by link - texverts are not welded""" row = 1.0/ring col = 1.0/divs cols = [col for i in range(divs)] if edgelens: totlen = 0.0 for elen in edgelens: totlen += elen cols = [i/totlen for i in edgelens] tverts = [] tsets = [] count = 0 umax = 0.0 umin = 0.0 splitring = [i+1 for i in range(inner,ring)] # Moving UV seam to inner ring of loop, where it will be less visible for i in range(inner): # The splitring list is ring, reordered splitring.append(i+1) for div in range(divs): col = cols[div] if div < divs-1: umax += cols[div] else: umax = 1.0 for r in range(ring): top = splitring[r] bottom = splitring[r]-1 if bottom == ring: bottom = 0 for i in range(4): tsets.append(count) count += 1 a = [row*top,umin] b = [row*top,umax] c = [row*bottom,umax] d = [row*bottom,umin] tverts.append(a) tverts.append(b) tverts.append(c) tverts.append(d) umin = umax return tverts,tsets def path_length(path): """Get the total length of the hull path""" length = 0.0 for i in range(len(path)): start = path[i] if i < len(path)-1: end = path[i+1] else: end = path[0] dist = end - start dist = Numeric.sqrt( pow(dist[0],2) + pow(dist[1],2) + pow(dist[2],2) ) length += dist return length def merge_geomdata(geom,verts,polys,sets,tverts,tpolys,tsets,group="",mat="Preview"): geom.merge_polys(polys,groups=[group],mat=mat) geom.merge_sets(sets) geom.merge_tpolys(tpolys) geom.merge_tsets(tsets) geom.merge_verts(verts) geom.merge_tverts(tverts) def make_prop(geom): verts = Numeric.array(geom.verts,Numeric.Float) polys = Numeric.array(geom.polys,Numeric.Int) sets = Numeric.array(geom.sets,Numeric.Int) tverts = Numeric.array(geom.tverts,Numeric.Float) tpolys = Numeric.array(geom.tpolys,Numeric.Int) tsets = Numeric.array(geom.tsets,Numeric.Int) newgeom = poser.NewGeometry() newgeom.AddGeneralMesh(polys,sets,verts,tpolys,tsets,tverts) newprop = scene.CreatePropFromGeom(newgeom,"newloop") class myGeom(object): def __init__(self): self.verts = [] self.polys = [] self.sets = [] self.tverts = [] self.tpolys = [] self.tsets = [] self.groups = [] self.mats = [] self.linklen = 0.0 self.centers = [] self.vertcount = 0 self.tvertcount = 0 self.setcount = 0 self.tsetcount = 0 def merge_verts(self,newverts): self.vertcount += len(newverts) for vi in range(len(newverts)): self.verts.append([i for i in newverts[vi]]) def merge_polys(self,newpolys,groups=[],mat="Preview"): count = self.setcount for pi in range(len(newpolys)): poly = newpolys[pi] self.polys.append([poly[0]+count,poly[1]]) self.groups.append([i for i in groups]) self.mats.append(mat) def merge_sets(self,newsets): self.setcount += len(newsets) count = self.vertcount for si in range(len(newsets)): self.sets.append(newsets[si]+count) def merge_tverts(self,newtverts): self.tvertcount += len(newtverts) for vi in range(len(newtverts)): self.tverts.append([i for i in newtverts[vi]]) def merge_tpolys(self,newtpolys): count = self.tsetcount for pi in range(len(newtpolys)): poly = newtpolys[pi] self.tpolys.append([poly[0]+count,poly[1]]) def merge_tsets(self,newtsets): self.tsetcount += len(newtsets) count = self.tvertcount for si in range(len(newtsets)): self.tsets.append(newtsets[si]+count) def AABB_plane_intersect(box,plane_norm,plane_D): """ Perform static AABB-plane intersection test. Returns: <0 Box is completely on the BACK side of the plane >0 Box is completely on the FRONT side of the plane 0 Box intersects the plane Adapted from '3D Math Primer for Graphics and Game Development', by Fletcher Dunn and Ian Parberry www.gamemath.com original code is available in downloads section of website. bounding box format is [minX,maxX,minY,maxY,minZ,maxZ] """ # Inspect the normal and compute the minimum and maximum D values. if plane_norm[0] > 0.0: minD = plane_norm[0] * box[0] maxD = plane_norm[0] * box[1] else: minD = plane_norm[0] * box[1] maxD = plane_norm[0] * box[0] if plane_norm[1] > 0.0: minD += plane_norm[1] * box[2] maxD += plane_norm[1] * box[3] else: minD += plane_norm[1] * box[3] maxD += plane_norm[1] * box[2] if plane_norm[2] > 0.0: minD += plane_norm[2] * box[4] maxD += plane_norm[2] * box[5] else: minD += plane_norm[2] * box[5] maxD += plane_norm[2] * box[4] # Check if completely on the front side of the plane if minD > plane_D: return 1 # Check if completely on the back side of the plane if maxD < plane_D: return -1 # We straddle the plane return 0 def lineline(A,B,C,D): """ Line-line intersection algorithm, returns point of intersection or None http://refactormycode.com/codes/1114-line-line-intersection-test Adapted from PyGame code posted by Mizipzor """ # ccw from http://www.bryceboe.com/2006/10/23/line-segment-intersection-algorithm/ def ccw(A,B,C): return (C[1]-A[1])*(B[0]-A[0]) > (B[1]-A[1])*(C[0]-A[0]) if ccw(A,C,D) != ccw(B,C,D) and ccw(A,B,C) != ccw(A,B,D): # formula from http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/ ua = float(((D[0]-C[0])*(A[1]-C[1]))-((D[1]-C[1])*(A[0]-C[0])))/float(((D[1]-C[1])*(B[0]-A[0]))-((D[0]-C[0])*(B[1]-A[1]))) ub = float(((B[0]-A[0])*(A[1]-C[1]))-((B[1]-A[1])*(A[0]-C[1])))/float(((D[1]-C[1])*(B[0]-A[0]))-((D[0]-C[0])*(B[1]-A[1]))) return (A[0]+(ua*(B[0]-A[0])), A[1]+(ua*(B[1]-A[1]))) return None def circle(pos, radius, precision=10, center=0, rot=0, ray1=None, ray2=None): """ http://ubuntuforums.org/showthread.php?t=946618 Adapted from openGL function posted by user crazyfuturamanoob. Arbitrary plane handling based on a post at MATLAB Central: http://www.mathworks.com/matlabcentral/newsreader/view_thread/164885 """ plane = 0 if (ray1 != None) and (ray2 != None): plane = 1 if type(pos) != "array": pos = Numeric.array(pos,Numeric.Float) pi = math.pi cverts = [] step = int(360/precision) for angle in range(0, 360, step): theta = pi*angle/180.0 cos = math.cos(theta) sin = math.sin(theta) if plane: # Apply rotation along an arbitrary axis cverts.append(pos + ((ray1*cos + ray2*sin) * radius)) else: if rot: cverts.append([pos[0], pos[1] + radius*cos, pos[2] + radius*sin]) else: cverts.append([pos[0] + radius*cos, pos[1], pos[2] + radius*sin]) if center: cverts.append([i for i in pos]) return cverts #================================================================================================= # Vector and matrix functions from Blender2Cal3D.py for Blender. # http://www-users.cs.umn.edu/~mein/blender/plugins/python/import_export/blend2cal3d/blender2cal3d.py # (Other versions of this script can be found online, with Google) # Poser matrices are compatible with Cal3D matrices, but not with Blender matrices. # Some functions have been altered from the original. # # (Xscale, 0.0, 0.0, 0.0), # (0.0, yScale, 0.0, 0.0), # (0.0, 0.0, zScale, 0.0), # (xTran, yTran, zTran, ) #================================================================================================= def matrix_invert(m): det = (m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2]) + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2])) if det == 0.0: return None det = 1.0 / det r = [ [ det * (m[1][1] * m[2][2] - m[2][1] * m[1][2]), - det * (m[0][1] * m[2][2] - m[2][1] * m[0][2]), det * (m[0][1] * m[1][2] - m[1][1] * m[0][2]), 0.0, ], [ - det * (m[1][0] * m[2][2] - m[2][0] * m[1][2]), det * (m[0][0] * m[2][2] - m[2][0] * m[0][2]), - det * (m[0][0] * m[1][2] - m[1][0] * m[0][2]), 0.0 ], [ det * (m[1][0] * m[2][1] - m[2][0] * m[1][1]), - det * (m[0][0] * m[2][1] - m[2][0] * m[0][1]), det * (m[0][0] * m[1][1] - m[1][0] * m[0][1]), 0.0, ] ] r.append([ -(m[3][0] * r[0][0] + m[3][1] * r[1][0] + m[3][2] * r[2][0]), -(m[3][0] * r[0][1] + m[3][1] * r[1][1] + m[3][2] * r[2][1]), -(m[3][0] * r[0][2] + m[3][1] * r[1][2] + m[3][2] * r[2][2]), 1.0, ]) return r def matrix_rotate(axis, angle): vx = axis[0] vy = axis[1] vz = axis[2] vx2 = vx * vx vy2 = vy * vy vz2 = vz * vz cos = math.cos(angle) sin = math.sin(angle) co1 = 1.0 - cos return [ [vx2 * co1 + cos, vx * vy * co1 + vz * sin, vz * vx * co1 - vy * sin, 0.0], [vx * vy * co1 - vz * sin, vy2 * co1 + cos, vy * vz * co1 + vx * sin, 0.0], [vz * vx * co1 + vy * sin, vy * vz * co1 - vx * sin, vz2 * co1 + cos, 0.0], [0.0, 0.0, 0.0, 1.0], ] def point_by_matrix(p, m): return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0], p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1], p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]] def matrix_translate(m, v): m[3][0] += v[0] m[3][1] += v[1] m[3][2] += v[2] return m def matrix_scale(fx, fy, fz): return [ [ fx, 0.0, 0.0, 0.0], [0.0, fy, 0.0, 0.0], [0.0, 0.0, fz, 0.0], [0.0, 0.0, 0.0, 1.0], ] def r2d(r): """Could also use math.degrees(r)""" #return round(r*180.0/math.pi,4) d = round(r*180.0/math.pi,4) if d > 360.0: d = d % 360 return d def d2r(d): """Could also use math.radians(d)""" return (d*math.pi)/180.0 def vector_normalize(v): l = Numeric.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]) if l == 0.0: return Numeric.array([v[0], v[1], v[2]],Numeric.Float) # Spanki - avoid divide-by-zero (test added) return Numeric.array([v[0] / l, v[1] / l, v[2] / l],Numeric.Float) def vector_normalize2d(v): l = Numeric.sqrt(v[0] * v[0] + v[1] * v[1]) if l == 0.0: return Numeric.array([v[0], v[1]],Numeric.Float) # Spanki - avoid divide-by-zero (test added) return Numeric.array([v[0] / l, v[1] / l],Numeric.Float) def vector_crossproduct(v1, v2): return [ v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0], ] def distance2d(p1,p2): p1 = Numeric.array(p1,Numeric.Float) p2 = Numeric.array(p2,Numeric.Float) dist = p2 - p1 dist = Numeric.sqrt( pow(dist[0],2) + pow(dist[1],2) ) return dist def distance3d(p1,p2): p1 = Numeric.array(p1,Numeric.Float) p2 = Numeric.array(p2,Numeric.Float) dist = p2 - p1 dist = Numeric.sqrt( pow(dist[0],2) + pow(dist[1],2) + pow(dist[2],2) ) return dist def vector_angle(v1, v2, r2d=0): """ Originally derived from blender2cal3d.py. Returns radians. if r2d is sent as 1, will return degrees. """ s = vector_length(v1) * vector_length(v2) if s == 0: return 0.0 f = vector_dotproduct(v1,v2) / s if f > 1.0: return 0.0 if f < -1.0: return math.pi / 2.0 if r2d: return round(math.degrees(math.acos(f))) return math.acos(f) def vector_length(v): if len(v) == 2: return Numeric.sqrt( pow(v[0],2) + pow(v[1],2) ) elif len(v) == 3: return Numeric.sqrt( pow(v[0],2) + pow(v[1],2) + pow(v[2],2) ) def vector_dotproduct(v1,v2): if len(v1) == 2: v1 = [v1[0],v1[1],0.0] if len(v2) == 2: v2 = [v2[0],v2[1],0.0] return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] #================================================================================================= # convex hull (Graham scan by x-coordinate) and diameter of a set of points # David Eppstein, UC Irvine, 7 Mar 2002 # http://code.activestate.com/recipes/117225-convex-hull-and-diameter-of-2d-point-sets/ # This code seems to return the correct set of points, but not in any useful order. #================================================================================================= def orientation2(p,q,r): '''Return positive if p-q-r are clockwise, neg if ccw, zero if colinear.''' return (q[1]-p[1])*(r[0]-p[0]) - (q[0]-p[0])*(r[1]-p[1]) def orientation3(p,q,r): return ((q - p) * (r - p).conjugate()).imag def hulls(Points): '''Graham scan to find upper and lower convex hulls of a set of 2d points.''' U = [] L = [] Points.sort() for p in Points: while len(U) > 1 and orientation2(U[-2],U[-1],p) <= 0: U.pop() while len(L) > 1 and orientation2(L[-2],L[-1],p) >= 0: L.pop() U.append(p) L.append(p) #return U,L return U[:-1] + L #================================================================================================= # Convex hull code # http://code.activestate.com/recipes/66527-finding-the-convex-hull-of-a-set-of-2d-points/ # This code can return a set which includes one or more inner points, creating a snarled path #================================================================================================= """ convexhull.py Calculate the convex hull of a set of n 2D-points in O(n log n) time. Taken from Berg et al., Computational Geometry, Springer-Verlag, 1997. Prints output as EPS file. When run from the command line it generates a random set of points inside a square of given length and finds the convex hull for those, printing the result as an EPS file. Usage: convexhull.py Dinu C. Gherman """ ###################################################################### # Helpers ###################################################################### def _myDet(p, q, r): """Calc. determinant of a special matrix with three 2D points. The sign, "-" or "+", determines the side, right or left, respectivly, on which the point r lies, when measured against a directed vector from p to q. """ # We use Sarrus' Rule to calculate the determinant. # (could also use the Numeric package...) sum1 = q[0]*r[1] + p[0]*q[1] + r[0]*p[1] sum2 = q[0]*p[1] + r[0]*q[1] + p[0]*r[1] return sum1 - sum2 def _isRightTurn((p, q, r)): "Do the vectors pq:qr form a right turn, or not?" #assert p != q and q != r and p != r if (p == q) or (q == r) or (p == r): return 0 if _myDet(p, q, r) < 0: return 1 else: return 0 def _isPointInPolygon(r, P): "Is point r inside a given polygon P?" # We assume the polygon is a list of points, listed clockwise! for i in xrange(len(P[:-1])): p, q = P[i], P[i+1] if not _isRightTurn((p, q, r)): return 0 # Out! return 1 # It's within! ###################################################################### # Public interface ###################################################################### def convexHull(P): "Calculate the convex hull of a set of points." # Get a local list copy of the points and sort them lexically. points = map(None, P) points.sort() # Build upper half of the hull. upper = [points[0], points[1]] for p in points[2:]: upper.append(p) while len(upper) > 2 and not _isRightTurn(upper[-3:]): del upper[-2] # Build lower half of the hull. points.reverse() lower = [points[0], points[1]] for p in points[2:]: lower.append(p) while len(lower) > 2 and not _isRightTurn(lower[-3:]): del lower[-2] # Remove duplicates. del lower[0] del lower[-1] # Concatenate both halfs and return. return tuple(upper + lower) #================================================================================================= # End convex hull #================================================================================================= #================================================================================================= # class myMesh # A container class for geometry data # Functions developed for TDMT project, 2007 # Some functions written or modified by Spanki #================================================================================================= class myMesh(object): def __init__(self,act,verts): self.act = act self.geom = act.Geometry() self.verts = verts self.polyverts(self.geom,self.geom.Polygons()) self.polyedges(self.pverts) self.vertpolys(self.geom,self.pverts) def get_norms(self): self.polynorms(self.pverts) #self.vertnorms_Geom() self.polyplanes(self.pverts) def polyverts(self,geom,polys): """ vertices by polygon - this is the Sets() list broken down by polygon index. Returns a list of Numeric arrays From TDMT Classic source code. """ self.pverts = [] gset = geom.Sets() for p in polys: l = p.NumVertices() s = p.Start() e = s + l vl = Numeric.array([v for v in gset[s:e]],Numeric.Int) self.pverts.append(vl) def vertpolys(self,geom,pgons,tex=0): """ polygons by vertex - each vert will have multiple listings returns a list of Numeric arrays """ if tex: self.vpolys = [[] for i in range(geom.NumTexVertices())] else: self.vpolys = [[] for i in range(geom.NumVertices())] for pvi in range(len(pgons)): for v in pgons[pvi]: if not pvi in self.vpolys[v]: self.vpolys[v].append(pvi) self.vpolys = [Numeric.array(i,Numeric.Int) for i in self.vpolys] def polynorms(self,pgons,verts=[]): """ [Spanki] compute normal for each polygon (don't rely on Poser supplied Normals - they're broken) returns a Numeric array """ self.pnorms = [[0.0,0.0,0.0] for i in range(len(pgons))] self.pnorms = Numeric.array(self.pnorms,Numeric.Float) if verts == []: verts = self.verts for p_i in range(len(pgons)): p = pgons[p_i] v0 = verts[p[0]] v1 = verts[p[1]] v2 = verts[p[2]] # Create 2 edge vectors to define a plane e1 = v1 - v0 e2 = v2 - v0 # Cross-product is normal to that plane vN = vector_normalize(vector_crossproduct(e1, e2)) self.pnorms[p_i] = vN def vertnorms_Geom(self,norms2=0): """ [Spanki] normals of vertices, computed as the average of the face normals of the polygons which use each vertex returns a Numeric array """ if norms2: self.raynorms = [[0.0,0.0,0.0] for i in range(len(self.vpolys))] self.raynorms = Numeric.array(self.vnorms,Numeric.Float) else: self.vnorms = [[0.0,0.0,0.0] for i in range(len(self.vpolys))] self.vnorms = Numeric.array(self.vnorms,Numeric.Float) for vi in range(len(self.vpolys)): polys = self.vpolys[vi] nx = 0; ny = 0; nz = 0 l = len(polys) if l == 0: # In some unusual geometries, there may be vertices with no polygon associations - we try to skip these. 1/26/08 #print "Stray vertex: %s, %s" %(vi,l) continue # If we don't skip these, we get a divide by zero crash error due to a bad mesh. for p in polys: nx += self.pnorms[p][0] ny += self.pnorms[p][1] nz += self.pnorms[p][2] n = [nx/l,ny/l,nz/l] n = vector_normalize(n) # Shouldn't need to do this, but it can't hurt if norms2: self.raynorms[vi] = n else: self.vnorms[vi] = n def polyedges(self,pgons,tris=0): """ edges of polygons as [start vert,end vert] """ self.edges = [[[0,0] for j in range(len(i))] for i in pgons] for p in range(len(pgons)): for v in range(len(pgons[p])): if v != len(pgons[p])-1: self.edges[p][v] = [pgons[p][v],pgons[p][v+1]] else: self.edges[p][v] = [pgons[p][v],pgons[p][0]] def polyplanes(self,pgons): """ planes of polygons tries to use a single vertex to calculate the plane, unless two axes of the first vertex are at 0.0, in which case it will use the average of all three vertices to calculate the plane. returns a Numeric array [Spanki] - I flipped the order of these, so that the average is used as preference (it's less likely to have any 0.0 coordinate) """ self.pplanes = [] for pvi in range(len(pgons)): px = 0; py = 0; pz = 0 n = self.pnorms[pvi] pv = pgons[pvi] for vert in pv: vx = self.verts[vert] px += vx[0] py += vx[1] pz += vx[2] if (abs(px) < FLT_EPSILON and abs(py) < FLT_EPSILON) or\ (abs(px) < FLT_EPSILON and abs(pz) < FLT_EPSILON) or\ (abs(py) < FLT_EPSILON and abs(pz) < FLT_EPSILON): vx = self.verts[self.tverts[pvi][0]] D = n[0] * vx[0] + n[1] * vx[1] + n[2] * vx[2] else: v_avg = [px/3,py/3,pz/3] D = 0 for i in range(3): D += n[i]*v_avg[i] self.pplanes.append(D) self.pplanes = Numeric.array(self.pplanes,Numeric.Float) def vertneighbors(self,pgons): """ neighbor verts of verts pgons is self.pverts or self.tverts """ self.vneighbors = [[] for i in range(len(self.vpolys))] for vi in range(len(self.vpolys)): buflist = [vi] # Need to exclude the vert itself! for ps in self.vpolys[vi]: for v in pgons[ps]: if not v in buflist: self.vneighbors[vi].append(v) buflist.append(v) def vertexPos(geom,worldspace=1,multiple=1.0): """ Pre-fetch vertex coordinates for faster access. Returns a Numeric array of vert coords by vert indices Send worldspace=0 keyword when calling function, to use localspace From TDMT Classic source code. """ numVerts = geom.NumVertices() verts = [[0.0,0.0,0.0] for i in range(numVerts)] verts = Numeric.array(verts,Numeric.Float) for i in range(numVerts): if worldspace: v = geom.WorldVertex(i) else: v = geom.Vertex(i) verts[i] = [v.X(),v.Y(),v.Z()] return verts #================================================================================================= # --- Bounding boxes, testing boxes --- #================================================================================================= def in_box(bbox,verts): """Simple bounding box check""" inbox = [0 for i in range(len(verts))] for vi in range(len(verts)): vert = verts[vi] if vert[0] >= bbox[0] and vert[0] <= bbox[1]: if vert[1] >= bbox[2] and vert[1] <= bbox[3]: if vert[2] >= bbox[4] and vert[2] <= bbox[5]: inbox[vi] = 1 return inbox def b_box_ock(vertpos): """ create bounding boxes """ minX = 1000000.0; maxX = -1000000.0 minY = 1000000.0; maxY = -1000000.0 minZ = 1000000.0; maxZ = -1000000.0 for i in range(len(vertpos)): tx = vertpos[i][0] ty = vertpos[i][1] tz = vertpos[i][2] if tx < minX: minX = tx if tx > maxX: maxX = tx if ty < minY: minY = ty if ty > maxY: maxY = ty if tz < minZ: minZ = tz if tz > maxZ: maxZ = tz return [minX,maxX,minY,maxY,minZ,maxZ] def box_center(box): """ find the center of the box To use results as a cylinder: use box_center x,z with vertex y Game gems: can also do (min + max)/2 for each axis. """ minX,maxX,minY,maxY,minZ,maxZ = box cx = (abs(minX-maxX)/2)+minX cy = (abs(minY-maxY)/2)+minY cz = (abs(minZ-maxZ)/2)+minZ return (cx,cy,cz) def mix_boxes(b1,b2,box=[],increase=0.0): """ merge two bounding boxes """ g = 1000000.0 box = [g,-g,g,-g,g,-g] for i in range(6): if (i+1)%2 != 0: # Odd is min if b1[i] < box[i]: box[i] = b1[i] elif (i+1)%2 == 0: if b1[i] > box[i]: box[i] = b1[i] for i in range(6): if (i+1)%2 != 0: # Odd is min if b2[i] < box[i]: box[i] = b2[i] elif (i+1)%2 == 0: if b2[i] > box[i]: box[i] = b2[i] if increase: box = increase_box(box,increase) return box def increase_box(box,increase): """ increase the bounding box size """ for i in range(6): if i%1 == 0: increase = -increase box[i] = box[i] + increase return box def box_verts(b1): """ Derive vertices from a bounding box """ return [ [b1[0],b1[2],b1[4]], [b1[0],b1[3],b1[4]], [b1[0],b1[3],b1[5]],[b1[0],b1[2],b1[5]], [b1[1],b1[2],b1[4]],[b1[1],b1[3],b1[4]], [b1[1],b1[3],b1[5]],[b1[1],b1[2],b1[5]] ] def testing_boxes(point,sz,name,disp,merge): """ build the testing boxes """ b = [point[0]-sz, point[0]+sz, point[1]-sz, point[1]+sz, point[2]-sz, point[2]+sz] box = build_box(b,name,disp,merge) return box def testing_boxes2d(point,sz,name,disp,merge): """ build the testing boxes """ b = [point[0]-sz, point[0]+sz, 0.0-sz, 0.0+sz, point[1]-sz, point[1]+sz] build_box(b,name,disp,merge) def build_box(b1,name,display,merge,vertarray=None): """ Create a box using the Poser geometry API b1 format is [minX,maxX,minY,maxY,minZ,maxZ] if merge == 1, prop will be merged with any pre-existing prop of the same name. """ addmesh = 0 if merge: props = [a for a in scene.Actors() if a.Name() == name and a.IsProp()] if len(props) >= 1: addmesh = 1 if addmesh: newbox = props[0] bbox = newbox.Geometry() else: bbox = poser.NewGeometry() if vertarray == None: Verts = Numeric.array([ [b1[0],b1[2],b1[4]], [b1[0],b1[3],b1[4]], [b1[0],b1[3],b1[5]], [b1[0],b1[2],b1[5]],[b1[1],b1[2],b1[4]],[b1[1],b1[3],b1[4]], [b1[1],b1[3],b1[5]],[b1[1],b1[2],b1[5]] ], Numeric.Float) else: # Use vertarray Verts = vertarray Polys = Numeric.array([[0,4],[4,4],[8,4],[12,4],[16,4],[20,4]],Numeric.Int) Sets = Numeric.array([3,2,1,0,4,5,6,7,5,4,0,1,6,5,1,2,7,6,2,3,4,7,3,0],Numeric.Int) bbox.AddGeneralMesh(Polys,Sets,Verts) if addmesh: newbox.SetGeometry(bbox) newbox.MarkGeomChanged() else: newbox = scene.CreatePropFromGeom(bbox,name) if display == 1: newbox.SetDisplayStyle(poser.kDisplayCodeEDGESONLY) if display == 2: newbox.SetDisplayStyle(poser.kDisplayCodeWIREFRAME) return newbox def build_plane(name,display=0): newplane = poser.NewGeometry() vertices = [[-0.25, 0.0, 0.25], [0.25, 0.0, 0.25], [0.25, 0.0, -0.25], [-0.25, 0.0, -0.25]] vertices = Numeric.array(vertices,Numeric.Float) polys = Numeric.array( [[0,3],[3,3]] ,Numeric.Int) sets = Numeric.array( [0,1,3,1,2,3] ,Numeric.Int) newplane.AddGeneralMesh(polys,sets,vertices) plane = scene.CreatePropFromGeom(newplane,name) #if display == 0: plane.SetDisplayStyle(poser.kDisplayCodeSHADEDOUTLINED) if display == 1: plane.SetDisplayStyle(poser.kDisplayCodeEDGESONLY) elif display == 2: plane.SetDisplayStyle(poser.kDisplayCodeWIREFRAME) scene.ProcessSomeEvents(1) scene.DrawAll() return plane start()