Notifications
Clear all

[Closed] Mini-Challenge #3

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

Hmm, i was mean sending from max to .net is more slower, or am wrong?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

it’s fast enough.

 lo1

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:

 lo1

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?

2 Replies
(@panayot)
Joined: 11 months ago

Posts: 0

i tested, not help

(@denist)
Joined: 11 months ago

Posts: 0

too bad…

I wish you could SnapShotAsMesh a group of objects, and get that as TriMesh, then assign that to a EMesh or EPoly…

1 Reply
 j83
(@j83)
Joined: 11 months ago

Posts: 0

Yeah, I tried that in about 5 different ways, no go.

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
	)
1 Reply
(@plastic)
Joined: 11 months ago

Posts: 0

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?

1 Reply
 lo1
(@lo1)
Joined: 11 months ago

Posts: 0

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.

Page 4 / 5