all that we doing now is trying to find optimal attach order. which is helpful for performance but it can’t change the timing dramatically. keep going. but… if we found the way to disable poly rebuilding on time of attach that would change everything.
most time of the rebuilding is taken by building normals and creating edge data (it’s why trimesh attach much faster than poly).
the best scenario will be to attach all node without rebuilding normals and edges, and finally do only one update for source node.
that’s a theory. but i don’t know how to do it, and not sure it’s possible at all.
sending from .net to max is slow. so we can stay with .net array
but who said it must be array list? it might be generic list or some other collection. i will not tell you what is faster. but try to check it yourself… for the learning purpose
What do you mean exactly? It is exactly twice as long as the number of nodes to attach.
For 1000 nodes, the whole part before entering the attach loop takes 22ms, which is not likely to be the bottleneck.
Less than 1ms for 1000 iterations.
You’re right, Ive checked, and making a local copy is slower, though the difference is less than 1ms for 1000 iterations.
:shrug:
I agree, the best result we can get from polyop.attach is what we already have due to optimal attach order.
But ironically, the algorithm I posted which does not use the most optimal order is faster than the one that does, so I am quite puzzled…
could anyone try to attach poly nodes with editable_poly property update set to manual? does it effect performance?
I wish you could SnapShotAsMesh a group of objects, and get that as TriMesh, then assign that to a EMesh or EPoly…
You might be able to get all vert positions in the objects and create a new mesh from that, but then you won’t get UVs and Textures, and Smoothing, ect… So prob. not worth it, heh. :banghead:
I tried to go multithreded but ran into some problems…
If I run it with more then 1 thread max crashes and it’s very unstable as it is with 1.
I saw some discussions about the backgroundworker where it was mentioned that some mxs functions won’t work with it, I guess attach is one of them.
here is my attempt:
struct progUpdater (
count,
current = 0,
pb,
fn increment =
(
current += 1
pb.value = 100 * current / count
)
)
global pbManager
struct hcNode (
val = 0,
left,
right,
obj,
count = 1,
verts = 0,
fn init =
(
if obj != undefined then
val = obj.numVerts
else (
if left != undefined then (
val += left.val
val += right.val
verts = left.verts + right.verts + left.val + right.val
count = left.count + right.count
)
)
),
fn mergeChildren =
(
local att = polyop.attach
if left != undefined then (
local a = left.mergeChildren()
local b = right.mergeChildren()
left = undefined
right = undefined
att a b
obj = a
verts += val
) else
pbManager.increment()
obj
),
start = init()
)
fn sortByVertNum a b =
(
a.val - b.val
)
fn insertInPlace arr new start: end: =
(
if end - start < 0 then
append arr new
else if end - start == 0 then (
if arr[start].val > new.val then
insertItem new arr start
else
insertItem new arr (start + 1)
) else (
local i = amin (start + (end - start) / 2) (end - 1)
if arr[i].val > new.val then
insertInPlace arr new start:start end:i
else if arr[i].val < new.val then
insertInPlace arr new start:(i + 1) end:end
else
insertItem new arr i
)
)
struct treeMonitor (
roots,
next = 0,
count = 0,
source,
occupied = false,
fn getRoot =
(
next += 1
occupied = false
roots[next]
),
fn mergeRoots =
(
local att = polyop.attach
for o in roots do
att source o.obj
),
fn done =
(
count += 1
if count == roots.count then
mergeRoots()
redrawViews()
)
)
global hcMergeTreeFN
fn hcMergeTreeFN =
(
global hcTreeMonitor
if hcTreeMonitor != undefined then (
hcTreeMonitor.occupied = true
local root = hcTreeMonitor.getRoot()
root.mergeChildren()
hcTreeMonitor.done()
)
)
fn foo source nodes pb:pb1 =
(
local numThreads = 1 --sysInfo.cpuCount
local nodeArr = for o in nodes collect hcNode obj:o
qsort nodeArr sortByVertNum
while nodeArr.count > numThreads do (
local left = nodeArr[1]
local right = nodeArr[2]
deleteItem nodeArr 2
deleteItem nodeArr 1
local new = hcNode left:left right:right
insertInPlace nodeArr new start:1 end:nodeArr.count
)
local count = 0
for o in nodeArr do (
count += o.count
verts += o.verts
)
pbManager = progUpdater count:count pb:pb1
/*
local att = polyop.attach
for o in nodeArr do (
o.mergeChildren()
att source o.obj
)
*/
global hcTreeMonitor = treeMonitor roots:nodeArr source:source
global hcMergeWorkers = #()
for i = 1 to numThreads do (
local newWorker = dotnetObject "System.ComponentModel.BackGroundWorker"
dotNet.addEventHandler newWorker "DoWork" hcMergeTreeFN
append hcMergeWorkers newWorker
while hcTreeMonitor.occupied do ()
newWorker.RunWorkerAsync()
)
)
fn customAttach source nodes pb:pb1 =
(
count = nodes.count
foo source nodes pb:pb1
source
)
I found that every operation that affects scene nodes crashes max, when used in a backgoundworker.
what if we could attach the trimesh values of the objects in a backgroundworker and when they are done create a new poly from that trimesh value?
I’ve tried going down this route, but I could not get meshop.attach to successfully attach two trimeshes without one of them being a node. Is it possible?
edit: scratch that, I was operating on the mesh itself and not a copy of it.