[Closed] Groups break and weld functions – optimizing
I have two function I use in my game meshes exporter.
First one is breaking given set of vertices and returns groups of “child” vertices peer each “source” one.
So i.e. you breaking one vert, then 3 new verts are created. Function returns all these 4 verts as one group.
Second function is oposite to one I descripted above. It welding given groups of vertices.
I.e you giving two sets of vertices, they will be welded into two verts (one for each set).
Everythink works correctly, but weldGrups function is very slow. Actually I no using standard max’s weld option, but change vert indices in faces. It’s becouse of if you weld some verts then some-1 verts are disapearing. Then vertice indices are updated and I had to update also indices in weldGroups input parameter. Now it’s much faster, but still to slow.
On my PC weldGroups execution for 10 segments teapot takes 55 seconds:argh:
I spend lot time on it, but I have no idea how to optimize it.
Code comes with testing interface, so you can run it. Input geometry should looks same as before, without smoothing changes or moved faces.
-- groups breakw/weld functions
if( TestFloater != undefined ) do closerolloutfloater TestFloater
function getFacesByVert object vert =
(
local faces_val = meshOp.getFacesUsingVert object #{vert}
local faces = #()
for i=1 to faces_val.count do
(
if( faces_val[i] ) then
append faces i
)
faces -- return
)
function getFacesByVerts object verts =
(
local faces_val = meshOp.getFacesUsingVert object verts
local faces = #()
for i=1 to faces_val.count do
(
if( faces_val[i] ) then
append faces i
)
faces -- return
)
function weldGroups mesh wGroups =
(
local face, vFaces, v, con
for i=1 to wGroups.count do
(
if( wGroups[i].count > 1 ) then -- least two verts to weld
(
--sort wGroups[i] -- ascending order
for j=2 to wGroups[i].count do
(
vFaces = getFacesByVert mesh wGroups[i][j]
for k=1 to vFaces.count do
(
face = getFace mesh vFaces[k]
con = true -- continue loop
for v=1 to 3 while con do -- face's vertices
(
if( face[v] == wGroups[i][j] ) then -- found the corner vertex that will be weld
(
face[v] = wGroups[i][1] -- set idx of first vertex in wg (all vertices are like target weld to it)
setFace mesh vFaces[k] face -- update face in mesh
con = false -- break loop
)
)
)
)
)
if( (TestRoll.pBar != undefined) and ((mod i 50) == 0) ) then TestRoll.pBar.value = (i*50.0/wGroups.count) -- debug progress bar (call one peer 50 times)
)
meshOps.removeIsolatedVerts mesh
)
function breakToGroups mesh verts =
(
local faces_indices = getFacesByVerts mesh verts
local faces = for i=1 to faces_indices.count collect (getFace mesh faces_indices[i])
breakGroups = for i=1 to mesh.numverts collect #(i)
meshop.breakVerts mesh verts -- break
local face, idx
for i=1 to faces.count do
(
face = getFace mesh faces_indices[i] -- get coresponding face
for j=1 to 3 do
(
idx = findItem breakGroups[faces[i][j]] face[j] -- check this verticew isn't already added
if( idx == 0 ) then
append breakGroups[faces[i][j]] face[j]
)
)
breakGroups -- return
)
-- testing interface
if( TestRoll != undefined ) then -- recreate if window already existing
DestroyDialog TestRoll
rollout TestRoll "Group Break/Weld testing"
(
button getBtn "S-T-A-R-T" width:280
progressbar pBar width:280
on getBtn pressed do
(
undo off
(
--disableSceneRedraw()
if( selection.count > 0 ) then
(
--obj = snapshotAsMesh selection[1]
obj = convertToMesh selection[1] -- result check in scene
-- break all vertices into groups
local groups = (breakToGroups obj obj.verts)
print( "Break\Weld groups: " + (groups as string) )
pBar.color = red
local t = timeStamp()
--weldGroups obj groups -- TEST FUNCTION
weldGroups obj.mesh groups -- TEST FUNCTION, result check
-- indicate done
pBar.color = green
pBar.value = 100
getBtn.text = ("WeldGroups execute time: " + (((timeStamp()-t)/1000.) as string) + "s")
print getBtn.text--*/
redrawViews()
)
else
messageBox "No selected!"
--enableSceneRedraw()
)
)
)
-- create the rollout window and add the rollout
CreateDialog TestRoll width:300
to make the correct welding you don’t need to recompute all vertex “groups” after every weld operation.
Try to understand the logic:
- You have a group of vertices to weld (say #(4, 19,126, 148)). After successful welding only vertex with lowest number (4) will stay. Higher numbers (19,126,148) will go away.
- This operation will not effect any vertices of the mesh with indexes lower then 4.
- All vertices with indexes higher then 19 will loose 1 index
- All vertices with indexes higher then 126 will loose 1 index more
- All vertices with indexes higher then 148 will loose 1 index more
all that you need is recalculate vertex indexes for all weld “groups” next to welded one:
the pseudo code is:
for k=1 to groups.count do
(
weld group[k]
[i] for i=k+1 to groups.count do recalculate groups
)
Yes Denis, exacly that I had doing:
Group indices updating function:
function removeWeldedVerts verts welded =
(
if( (welded.count > 1) and (verts.count > 1) ) then -- weld needs least two vertices
(
local con -- for break loops
--sort verts -- ascending order
--sort welded
for i=1 to verts.count do
(
con = true
for j=welded.count to 1 by -1 while con do
(
if( verts[i] > welded[j] ) then
(
verts[i] -= (j-1) -- how many vertices before this vertice has disapear
con = false -- break loop
)
else
verts[i] = welded[1] -- this vertice is in group of welded, so after weld it will has idx of first in group
)
)
)
verts -- return
)
And groupsWelding code:
local welded = #() -- welded vertices
for i=1 to weldGroups.count do
(
removeWeldedVerts weldGroups[i] welded -- correct indices in array that will be weld
meshOp.weldVertSet mesh weldGroups[i] -- weld the group
join welded weldGroups[i] -- join just welded to welded vertices array
sort welded -- required for correct working of removeWeldedVerts
--ProgressDialog.setCurrProgress (i*1000/weldGroups.count) -- my own progress dialog script
)--*/
It is slower than code I posted before.
you are doing not what exactly the same as i said…
the code requires sorted vertex index arrays:
for k=1 to weld_groups.count do
(
group = weld_groups[k]
for i=k+1 to weld_groups.count do
(
next = weld_group
n = 1
while n < group.count do
(
n += 1
for j=1 to next.count where next[j] < group[n] do next[j] -= 1
)
)
)
-- after that:
for g in weld_groups where g.count > 1 do [b]<weld g>[/b]
ps. i’m writing from my cell phone and can’t check the code. also i’m sure that my code might be optimized very well.
You code isn’t finished, but I tried gues what you was thinking about and I created this:
for i=1 to (wGroups.count-1) do
(
group = wGroups[i]
for j=group.count to 1 by -1 do
(
for k=i+1 to wGroups.count do
(
next = wGroups[k]
for m=next.count to 1 by -1 do
(
if( group[j] < next[m] ) then
next[m] -= 1
else
if( group[j] == next[m] ) then
next[m] = group[1]
)
)
)
if( TestRoll != undefined ) then
TestRoll.pBar.value = (i*100.0/wGroups.count) -- debug progress bar
)
But it needs more than 4 minutes to execute
Later I created this:
function removeWeldedVerts verts welded =
(
if( (welded.count > 1) and (verts.count > 1) ) then -- weld needs least two vertices
(
if( verts[verts.count] > welded[1] ) then
(
if( verts[1] < welded[welded.count] ) then
(
local i = welded.count
local wVerts = welded.count
for j=verts.count to 1 by -1 where (i>0 and verts[j]>welded[1]) do
(
while( verts[j] < welded[i] ) do i -= 1
verts[j] -= i
)
)
else
(
for i=1 to verts.count do
verts[i] -= welded.count
)
)
)
)
and welding function:
function weldGroups mesh wGroups =
(
local welded = #(), lastWelded
for i=1 to wGroups.count do
(
sort wGroups[i]
lastWelded = #(); join lastWelded wGroups[i] -- copy the group
removeWeldedVerts wGroups[i] welded -- update indices
meshOp.weldVertSet mesh wGroups[i] -- weld the group
deleteItem lastWelded 1 -- delete first vert (it wasn't deleted when weld)
join welded lastWelded -- add last welded to welded group
sort welded
if( TestRoll != undefined ) then
TestRoll.pBar.value = (i*100.0/wGroups.count) -- debug progress bar
)
)
It takes 15 seconds (10 segments teapot). I hope it can be still optimized.
I don’t know how to create independend copy of array. I done it that way:
lastWelded = #(); join lastWelded wGroups[i] -- copy the group
but should be better solution
if you wanna copy an array (or any value) you can use the ‘copy’ function for nested stuff use the ‘deepCopy’ function