Voxelize Meshes Script
February 10th, 2010This script will voxelize selected meshes over the frame range of the timeline.
It is currently rather slow.
Pymel code:
### start: voxelize meshes v.1
from pymel import *
from math import fmod
import pymel.core.datatypes as dt
import maya.OpenMaya as om
import random, time
global cubeCount
cubeCount = 0
# A simple wrapper for the maya api function allIntersections to test if point lies inside of mesh - returns true or false
#
# point is the position of interest in world space
# direction is the ray direction to test in
# mesh is the geometry to test against
def rayIntersect(mesh, point, direction=(0.0, 1.0, 0.0)):
om.MGlobal.selectByName(mesh)
sList = om.MSelectionList()
#Assign current selection to the selection list object
om.MGlobal.getActiveSelectionList(sList)
item = om.MDagPath()
sList.getDagPath(0, item)
item.extendToShape()
fnMesh = om.MFnMesh(item)
raySource = om.MFloatPoint(point[0], point[1], point[2], 1.0)
rayDir = om.MFloatVector(direction[0], direction[1], direction[2])
faceIds = None
triIds = None
idsSorted = False
testBothDirections = False
worldSpace = om.MSpace.kWorld
maxParam = 999999
accelParams = None
sortHits = True
hitPoints = om.MFloatPointArray()
hitRayParams = om.MFloatArray()
hitFaces = om.MIntArray()
hitTris = None
hitBarys1 = None
hitBarys2 = None
tolerance = 0.0001
hit = fnMesh.allIntersections(raySource, rayDir, faceIds, triIds, idsSorted, worldSpace, maxParam, testBothDirections, accelParams, sortHits, hitPoints, hitRayParams, hitFaces, hitTris, hitBarys1, hitBarys2, tolerance)
result = int(fmod(len(hitFaces), 2))
#clear selection as may cause problem if the function is called multiple times in succession
om.MGlobal.clearSelectionList()
return result
# progress bar, enabling "Esc"
def makeProgBar(length):
global gMainProgressBar
gMainProgressBar = mel.eval('$tmp = $gMainProgressBar');
cmds.progressBar( gMainProgressBar,
edit=True,
beginProgress=True,
isInterruptable=True,
maxValue=length
)
def promptNumber():
result = cmds.promptDialog(
title='Grow Shrub',
message='Block size:',
text="1",
button=['OK', 'Cancel'],
defaultButton='OK',
cancelButton='Cancel',
dismissString='Cancel')
if result == 'OK':
return float(cmds.promptDialog(query=True, text=True))
else: return 0
def doit1(cubeSize):
global cubeCount
# get the bounding box of the ctrl
xdist = abs(xmin)+abs(xmax)
ydist = abs(ymin)+abs(ymax)
zdist = abs(zmin)+abs(zmax)
cubeCount = xdist * ydist * zdist / cubeSize**3
print "Generating", int(cubeCount), "cubes..."
print "Press ESC to cancel"
makeProgBar(cubeCount)
fac = 1/cubeSize
# make an array of cubes to encompass the bounding box
for x in range(xmin*fac, xmax*fac+1):
for y in range(ymin*fac, ymax*fac+1):
for z in range(zmin*fac, zmax*fac+1):
stepint = 1
if cmds.progressBar(gMainProgressBar, query=True, isCancelled=True ):
break
return 0
cmds.progressBar(gMainProgressBar, edit=True, step=1)
# create and place a cube
cube = polyCube(sz=1, sy=1, sx=1, cuv=4, d=cubeSize, h=cubeSize, w=cubeSize, ch=1)[0]
xform(t=(x*cubeSize, y*cubeSize, z*cubeSize))
cubes.append(cube)
# set a control object
if len(selected()) == 0 or \
objectType(selected()[0].getShape()) != "mesh":
result = cmds.confirmDialog(
title='Mesh selection',
message='Please select a mesh.',
button=['OK'])
else:
startTime=timerX()
cubeSize = promptNumber()
ctrl = selected()
for c in ctrl:
c.visibility.set(1)
firstFrame = int(playbackOptions(query=1, min=1))
lastFrame = int(playbackOptions(query=1, max=1))
duration = int(lastFrame-firstFrame)
print "duration*len(ctrl):", duration*len(ctrl)
makeProgBar(duration*len(ctrl))
cmds.progressBar(gMainProgressBar, edit=True, beginProgress=1)
bb = ctrl[0].getBoundingBox()
xmin = bb[0][0]
xmax = bb[1][0]
xdist = abs(xmin)+abs(xmax)
ymin = bb[0][1]
ymax = bb[1][1]
ydist = abs(ymin)+abs(ymax)
zmin = bb[0][2]
zmax = bb[1][2]
print "Finding bounding box of animation..."
print "Press ESC to cancel"
# find outer boundaries of animation
for f in range(firstFrame,lastFrame):
for c in ctrl:
if cmds.progressBar(gMainProgressBar, query=1, isCancelled=1 ):
break
currentTime(f)
cmds.progressBar(gMainProgressBar, edit=1, step=1)
bb = c.getBoundingBox()
xmin = min(xmin, bb[0][0])
xmax = max(xmax, bb[1][0])
ymin = min(ymin, bb[0][1])
ymax = max(ymax, bb[1][1])
zmin = min(zmin, bb[0][2])
zmax = max(zmax, bb[1][2])
cmds.progressBar(gMainProgressBar, edit=1, endProgress=1)
# make cubes array
cubes = []
doit1(cubeSize)
cmds.progressBar(gMainProgressBar, edit=1, endProgress=1)
makeProgBar(duration*cubeCount)
cmds.progressBar(gMainProgressBar, edit=1, beginProgress=1)
print "Animating visibility over", duration, "frames..."
print "Press ESC to cancel"
# animate cube visibility
for f in range(firstFrame,lastFrame): # for each frame
currentTime(f, edit=1, update=1)
for x in cubes: # for each cube
x.visibility.set(1)
for x in cubes: # for each cube
currentTime(f)
if cmds.progressBar(gMainProgressBar, query=1, isCancelled=1 ):
break
cmds.progressBar(gMainProgressBar, edit=1, step=1)
for c in ctrl:
ctrlLoc = dt.Vector(c.t.get())
key = keyframe(x, t=(f,f), at="scale", valueChange=1, query=1)
if key == [] or key[0] != 1.0:
setKeyframe(x, attribute = "scale", v = 0, t = f)
# get the vector from x to ctrl
xLoc = x.t.get()
ctrlVec = dt.Vector(xLoc-ctrlLoc).normal()
sc = rayIntersect(c, xLoc, ctrlVec)
if sc == 1:
setKeyframe(x, attribute = "scale", v = sc, t = f)
currentTime(f, edit=1, update=1)
cutKey(ctrl, time=(0,(cmds.findKeyframe(which='last'))), attribute='visibility', clear=1, option='keys')
#c.visibility.set(0)
cmds.progressBar(gMainProgressBar, edit=1, endProgress=1)
totalTime = timerX(startTime=startTime)
print("Total Time: "+str(totalTime))
### end voxelize meshes v.1
« previously: Pivot | Home | next: Voxelize Meshes Script v.2 »
February 12th, 2010 at 11:30 am
Love it. I think something like this would benefit from being developed as a maya plug-in. Perhaps faster execution time and maybe even a maya node that you can just plug the geo into, set frame range.
Great stuff.
February 12th, 2010 at 11:48 am
I’d love to make it a plug-in, at the moment it requires so much preprocessing it wouldn’t work for something that had to evaluate every frame. There’s another approach I want to try though.
Will definitely have to be faster.