[Closed] Looking for Voxel generation script
Hi! I’m looking for a script(or a plugin) that would turn any given object in to grid of voxels similar to this one ( http://www.scriptspot.com/3ds-max/scripts/voxel-generator )
but:
- MUCH faster,
- dynamicly update the voxels for animated objects,
- sample textures,
Or maybe someone has an idea how to write such a script.
I have a very poor knowlege of scripting, but I think it shouldn’t be too hard,
plugins like Krakatoa or FumeFX create thousends of voxel particles in viewport within less then a second, turning those in to boxes should be simple IMO
this guy here is trying to create something similar
( http://maltaannon.com/blog/voxel-rendering-in-3ds-max/ )
thanks in advance
Funny that you think it’s simple…I don’t think it’s simple at all, especially with a script.
Doing ray intersection tests is slow with maxscript, and generating thousands of objects is also slow.
For turning particles into boxes, that should be easy indeed, you don’t need a script for that?
As others have said before me, this is NOT an easy task to do in a script.
I have written a similar script a while ago that is a bit faster but still not close to what you are asking for. If you want to give it a try, here it is:
(
fn isInVolume pos vol =
(
vol.normal.enabled = true
local r = ray pos [0,0,1]
local i = intersectRayEx vol r
if i != undefined then (
local s = distance pos i[1].pos
local k
vol.normal.enabled = false
local j = intersectRayEx vol r
if j != undefined and s > (k = distance pos j[1].pos) then
#(false, k)
else (
local n = getFaceNormal vol i[2]
local d = dot n i[1].dir
if d < 0 then
#(true, s)
else
#(false, s)
)
) else
#(false, 99999999)
)
fn createVoxelBoxes obj size = (
max create mode
--with redraw off (
local bb = nodeLocalBoundingBox obj
local a = box width:size length:size height:size
local m = normalModifier flip:true unify:true
addModifier obj m
for x = bb[1].x to bb[2].x by size do (
for y = bb[1].y to bb[2].y by size do (
local z = bb[1].z
while z <= bb[2].z do (
local p = [0, 0, 0]
p.x = x + size / 2.0
p.y =y + size / 2.0
p.z = z + size / 2.0
local q = isInVolume p obj
if not q[1] then
z += q[2] - (mod q[2] size) + size
else (
local arr = #()
local b = instance a
b.pos = p - [0, 0, size / 2.0]
append arr b
z += size
while q[2] > size do (
p.z += size
z += size
q[2] -= size
b = instance a
b.pos = p - [0, 0, size / 2.0]
append arr b
)
if arr.count == 1 then
arr[1].wirecolor = (green + blue) * 0.5
else (
for i = 1 to arr.count do
arr[i].wirecolor = (green * (arr.count - i) + blue * (i - 1)) / (arr.count - 1)
)
)
)
)
redrawViews()
gc()
)
deleteModifier obj m
delete a
--)
)
delete $Box*
local obj = $
local boxSize = 3
if isValidNode obj then (
local ts = timeStamp()
createVoxelBoxes obj boxSize
format "%
" ((timeStamp() - ts) / 1000.0)
)
gc()
OK
)
it has no interface so it will voxelize the selected (1) object into boxes in size 3
you can edit the voxel boxes size by changing the value of the variable named boxSize at the bottom of the script.
hope this somehow helps…
matan.
Thanks for sharing the script Matan, could not evaluate it though:(
It gives me this:
– Syntax error: at ), expected <factor>
– In line: )
(Max 2009 64 bit)
Yes, your probably right about simplicity, but maybe ray intersection is a wrong way to go…
I have some sort of idea in my mind, but dont know how to apply it, here it is:
Lets take for example Krakatoa PRT Volume Object:
(im talking about things that you see in the viewport only)
- PRT Volume Object converts any given object to voxel particles in a second, spacing of voxels is easy ajustible on the fly
- PRT Volume Object will dynamicly recieve any changes made with original object (modifiers etc…)
- PRT Volume Object sample materials and textures from the original one
All that you experience in a viewport at realtime but as a particle grid (or sprites), so
THE QUESTION IS: how to access this viewport data and convert those particles to boxes
same thing applies to FumeFX
here is a nice workaround for you (no scripting at all)
- create a ‘plane’ as the base of the voxel grid.
- duplicate the plane along the z axis in an even distribution as many times as required.
- attach all the planes together to form the voxel grid.
- add a ‘volume select’ modifier and use ‘select by mesh object’ and ‘invert’ to select all vertexes of the grid that are outside the mesh that you want to voxelize.
- add a ‘delete mesh’ modifier to delete all the unneeded vertexes.
- use a ‘scatter’ object (from the compound geometry category) to scatter a box on every vertex of the grid.
hope this helps,
matan.
Matan!!! Your genius!!! Works perfect, fast, clean and no coding:)
I used shell instead of scattering boxes, looks the same but less polys,
now the quastion is what to do with textures;)
Anyway, thanks a lot man!!
Going from Prt Volume -> into particle flow via the prt operators for the boxes is quite easy… then you have a few options for getting colors onto the boxes as well.
Sounds sweet SoLiTuDe, could you share some more details on that technic?
- Create a PRT Volume object and pick the source mesh. Set View Spacing to be the same as Render Spacing (this is the Voxel Size)
- Open Krakatoa GUI, switch to Save Particles To File Sequence, enter a path and Save (one or more frames, depending on whether you want a static frame or an animation)
- Create a PRT Loader, pick the saved file or sequence
- Open Particle View, create a Standard Flow, replace Birth with Krakatoa PRT Loader Birth, pick the PRT Loader.
- Delete the Position, Speed and Rotation ops, switch the Shape to Cube with size equal to the PRT Volume voxel size, switch Display to Geometry
At this point, you should have your voxelized model as a particle system.
I would hope someday we will remove the need for steps 2 and 3 and allow the PRT Loader Birth to pick a PRT Volume directly.
- If you saved a sequence, also add a Krakatoa PRT Loader Update operator and pick the PRT Loader to update the positions on every frame.
NOTE: PFlow Tools Box #2 has a Birth operator to create particles in a grid inside the volume of a mesh, but I find the PRT Volume much more precise (it can deal effectively even with open volumes, planes and, as I discovered yesterday, closed or renderable splines!). PRT Volume is based on level set conversion code from our Flood fluid simulator and is quite solid.
NOTE 2: There was a “A Day In The Life Of A Technical Director” Master Class posted on the Subscription Center page of Max where I presented a fully scripted way to convert a mesh to PFlow Voxels, but only the surface, not the volume. You could take a look at that if you have access to the Subscription pages. Also, you can change the PRT Volume to create particles only around the surface by using the Shell parameters.
Very nice info in this thread. But wouldn’t it slow down pflow in max viewport? As pflow isn’t multithreaded and loading particles in volume of complex geometry sometimes slow.
Is it possible PRT volume birth would be faster than standard pflow volume loading?
Well, the PRT Volume has been pre-calculated, but it shouldn’t take too long to generate on the fly – creating 2.8 million particles from 1 million polygons takes around 7 seconds incl. the normals acquisition.
(See http://software.primefocusworld.com/software/support/krakatoa/render_geometry_volumes.php#Example )
So the PFlow only reads pre-saved particles from disk which is really fast, and we are not doing millions of particles in this example.
The standard PFlow Position Object operator in Volume mode is SLOW! It is because it does not use any acceleration structures and has to do brute-force seeding of particles and checking whether they are in the volume.
The Box #2 operator is quite fast, but it can leak in complex cases (I have tested it with the same Buddha model and it wasn’t perfect).
The PRT Volume creates a watertight level set (it is the code we use to convert mesh objects into data that can be used in our fluid simulations), then the particles are seeded into the voxels and checked against the surface to ensure they are really inside. See examples here: http://software.primefocusworld.com/software/support/krakatoa/prt_volume_grid_and_random_particle_generation.php