On 13/05/2014 at 01:24, xxxxxxxx wrote:
Hi all,
I created a voxelizer with the old school thinking particles modul, that uses the ray collider as a polygon detector in Zaxis.
Just wanted to share it.
And thanks for helping me to learn all the stuff!
One question is left: is it possible to read(and only read) the Max Particles value, to inform the user that
his voxels may exceed the given limit? -script line 240-
######################################################################################
# Copyright (c) 2014 Martin Albertshauser #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in #
# all copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN #
# THE SOFTWARE. #
######################################################################################
##_________________________________monkeyvoxel______________________________________##
#__________________This script voxelizes closed meshes_______________________________#
######################################################################################
import c4d
import math
from c4d import utils,gui
from c4d.utils import SendModelingCommand
def axisreset(op) :
oldm= op.GetMg()
points= op.GetAllPoints()
pcount= op.GetPointCount()
bbox= op.GetMp()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
op.SetAbsRot(c4d.Vector(0,0,0))
newm= op.GetMg()
for p in xrange(pcount) :
op.SetPoint(p,~newm*oldm*points[p])
op.Message(c4d.MSG_UPDATE)
oldm2= op.GetMg()
points2= op.GetAllPoints()
bb2= op.GetMp()
glop= oldm*bbox
op.SetAbsPos(c4d.Vector(glop))
newm2= op.GetMg()
for p in xrange(pcount) :
op.SetPoint(p,~newm2*oldm2*points[p])
op.Message(c4d.MSG_UPDATE)
return
def voxel(xs,ys,zs) :
#Build a voxel object
vox= c4d.BaseObject(c4d.Opolygon)
vox.ResizeObject(8,6)
vox.SetPoint(0,c4d.Vector(-xs/2,-ys/2,-zs/2))
vox.SetPoint(1,c4d.Vector(-xs/2,ys/2,-zs/2))
vox.SetPoint(2,c4d.Vector(xs/2,ys/2,-zs/2))
vox.SetPoint(3,c4d.Vector(xs/2,-ys/2,-zs/2))
vox.SetPoint(4,c4d.Vector(-xs/2,-ys/2,zs/2))
vox.SetPoint(5,c4d.Vector(-xs/2,ys/2,zs/2))
vox.SetPoint(6,c4d.Vector(xs/2,ys/2,zs/2))
vox.SetPoint(7,c4d.Vector(xs/2,-ys/2,zs/2))
vox.SetPolygon(0,c4d.CPolygon(0,1,2,3))
vox.SetPolygon(1,c4d.CPolygon(4,5,1,0))
vox.SetPolygon(2,c4d.CPolygon(7,6,5,4))
vox.SetPolygon(3,c4d.CPolygon(3,2,6,7))
vox.SetPolygon(4,c4d.CPolygon(1,5,6,2))
vox.SetPolygon(5,c4d.CPolygon(0,4,7,3))
vox.Message (c4d.MSG_UPDATE)
return vox
def ray(op,rayposition,rayzdirection,raylength,xdim,ydim,zdim,Zcount,parSys,parGroup,parLife,pcounter) :
HitList= []
PosList= []
matr= op.GetMg()
precision= 6
#Initialize the collider
collider= c4d.utils.GeRayCollider()
collider.Init(op,True)
#Start the ray
inter= collider.Intersect(rayposition,rayzdirection,raylength)
if inter== True:
count= collider.GetIntersectionCount()
collision= 0
#Loop through all collisions
while collision< count:
hitposition= collider.GetIntersection(collision)["hitpos"]
#Limit the accuracy of Zpositions in the HitList because of the rounding errors with real type calculation at BitLimit with a precision value
hitposition.z= round(hitposition.z,precision)
#Fit the voxel´s Zposition in the grid
if hitposition.z>= 0:
hitposition.z= (math.ceil(hitposition.z/zdim))*zdim
if Zcount % 2== 0:
hitposition.z= hitposition.z-zdim/2
else:
hitposition.z= hitposition.z-zdim
else:
hitposition.z= (math.floor(hitposition.z/zdim))*zdim
if Zcount % 2== 0:
hitposition.z= hitposition.z+zdim/2
else:
hitposition.z= hitposition.z+zdim
if hitposition.z not in HitList:
backface= collider.GetIntersection(collision)["backface"]
HitList.append(hitposition.z)
PosList.append([hitposition,backface])
collision+= 1
#Sort the PosList in Zdirection
PosList= sorted(PosList,key= lambda x: x[0][2])
#Place voxels on every unique collision position
#and fill the gaps between them with voxels
for i,position in enumerate(PosList) :
if position[1]== False and PosList[i-1][1]!= False :
x= position[0].x
y= position[0].y
z= position[0].z
z1= PosList[(i-1)][0].z
zdiv= ((z-z1)/zdim)-1
i= +1
for g in xrange(int(zdiv)) :
z2= z-(g+1)*zdim
vec2= c4d.Vector(x,y,z2)
parSys.SetGroup(pcounter, parGroup)
parSys.SetLife(pcounter, parLife)
parSys.SetPosition(pcounter, (vec2*matr))
pcounter+= 1
parSys.SetGroup(pcounter, parGroup)
parSys.SetLife(pcounter, parLife)
parSys.SetPosition(pcounter, (position[0]*matr))
pcounter+= 1
return pcounter
def main() :
#Timer start
t= c4d.GeGetTimer()
#Make sure there is an active object
if op== None: return None
#Start an undo sequence
doc.StartUndo()
#Instantiate the object and reset the axis to boundingbox center:
#Ray collider works in local space, therefore axis reset is needed
testop= SendModelingCommand(command= c4d.MCOMMAND_CURRENTSTATETOOBJECT, list= [op.GetClone()], doc= doc)
if not testop : return
obj= testop[0]
axisreset(obj)
#Set voxel gaps:
xgap= 1
ygap= 1
zgap= 1
#Set voxel dimension:
xdim= 30
ydim= 30
zdim= 30
#Calculate the voxelgrid:
#If a mulitple of voxeldimension fits exactly into boundigboxsize, take it.
#Otherwise round up the count with a ceiling function, that the voxels covers the mesh
boundingbox= obj.GetRad()*2
CheckXcount= boundingbox.x/xdim
CeilXcount= math.ceil(CheckXcount)
if c4d.utils.CompareFloatTolerant(CheckXcount+1.0, CeilXcount)== True:
Xcount= CheckXcount
else:
Xcount= CeilXcount
CheckYcount= boundingbox.y/ydim
CeilYcount= math.ceil(CheckYcount)
if c4d.utils.CompareFloatTolerant(CheckYcount+1.0, CeilYcount)== True:
Ycount= CheckYcount
else:
Ycount= CeilYcount
CheckZcount= boundingbox.z/zdim
CeilZcount= math.ceil(CheckZcount)
if c4d.utils.CompareFloatTolerant(CheckZcount+1.0, CeilZcount)== True:
Zcount= CheckZcount
else:
Zcount= CeilZcount
#Calculate the origin of the VoxelGrid
Xorg= (Xcount*xdim)/2-xdim/2
Yorg= (Ycount*ydim)/2-ydim/2
Zorg= (Zcount*zdim)/2
#Basesettings of particles
if doc.GetParticleSystem()== None:
dialog=gui.MessageDialog("could not find 'Thinking Particles' module",c4d.GEMB_OK)
if dialog== 1:
return
else:
parSys= doc.GetParticleSystem()
parSys.FreeAllParticles()
doc.AddUndo(c4d.UNDOTYPE_CHANGE, parSys)
parMax= int((Xcount+1)*(Ycount+1)*(Zcount+1))
#Warn the user that the particles may be out of range
#don´t know how to access this Value:______________[IDC_TP_NUMLIMIT]____________________________________________
if parMax>100000:
dialog=gui.MessageDialog("Particle count exceeded! \nPlease raise the 'Max. Partikel' value.",c4d.GEMB_OK)
parGroup= parSys.AllocParticleGroup()
parGroup.SetTitle(op.GetName())
parGroup[c4d.PGROUP_NAME]= (str(op.GetName())+"_Voxels")
parGroup[c4d.PGROUP_VIEWTYPE]= 0
parGroupGlob= parSys.GetRootGroup()
parSys.SetPGroupHierarchy(parGroupGlob, parGroup, c4d.TP_INSERT_UNDERFIRST)
parLife= doc.GetMaxTime()
parSys.AllocParticles(parMax)
#Set the direction and length of the ray that the whole boundingbox is hit by the ray
rayzdirection= c4d.Vector(0,0,-1)
raylength= boundingbox.z+zdim
#Send rays
pcounter= 0
for py in xrange(int(Ycount)) :
y= float(ydim*py)
for px in xrange(int(Xcount)) :
x= float(xdim*px)
Zgrid= c4d.Vector((Xorg-x),(Yorg-y),(Zorg+zdim/2))
#recursivly raising the counter and call the rayfunction
pcounter= ray(obj,Zgrid,rayzdirection,raylength,xdim,ydim,zdim,Zcount,parSys,parGroup,parLife,pcounter)
#Objects,Tag: set and insert
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
op.SetEditorMode(c4d.MODE_OFF)
op.SetRenderMode(c4d.MODE_OFF)
cloner= c4d.BaseObject(1018544)
cloner[c4d.ID_MG_MOTIONGENERATOR_MODE]= 0
cloner[c4d.MG_OBJECT_LINK]= parGroup
cloner[c4d.MGCLONER_FIX_CLONES]= False
cloner[c4d.MG_OBJECT_ALIGN]= True
cloner.SetName(str(op.GetName())+"_Voxels")
doc.InsertObject(cloner)
display= cloner.MakeTag(c4d.Tdisplay)
display[c4d.DISPLAYTAG_AFFECT_DISPLAYMODE]= True
display[c4d.DISPLAYTAG_SDISPLAYMODE]= 4
display[c4d.DISPLAYTAG_WDISPLAYMODE]= 2
doc.AddUndo(c4d.UNDOTYPE_NEW,cloner)
vox= voxel(xdim-xgap,ydim-ygap,zdim-zgap)
vox.SetName("Voxel")
vox.InsertUnder(cloner)
doc.AddUndo(c4d.UNDOTYPE_NEW,vox)
random= c4d.BaseObject(1018643)
random.SetName("Voxel_Color")
random.InsertBefore(cloner)
doc.AddUndo(c4d.UNDOTYPE_NEW,random)
random[c4d.ID_MG_BASEEFFECTOR_COLOR_MODE]= 3
random[c4d.ID_MG_BASEEFFECTOR_POSITION_ACTIVE]= False
inexcludeList= cloner[c4d.ID_MG_MOTIONGENERATOR_EFFECTORLIST]
inexcludeList.InsertObject(random, 1)
cloner[c4d.ID_MG_MOTIONGENERATOR_EFFECTORLIST]= inexcludeList
doc.EndUndo()
c4d.EventAdd(c4d.EVENT_FORCEREDRAW)
time1= c4d.GeGetTimer() - t
print str(parSys.GetGroupParticleCount(parGroup, subgroups= False))+" build in "+ str(time1) + "msec"
if __name__=='__main__':
main()