Notifications
Clear all

[Closed] Mini-Challenge #3

found a way! (but still not so stable)

	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 = meshop.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 = meshop.attach
			
			for o in roots do
				att source o.obj
			
			source = mesh mesh:source
			convertTo source Editable_Poly
		),
		
		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 = 10 --sysInfo.cpuCount
		local nodeArr = #()
		for o in nodes do (
			append nodeArr (hcNode obj:(snapshotAsMesh o))
			delete 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
		
		global hcTreeMonitor = treeMonitor roots:nodeArr source:(snapshotAsMesh source)
		delete source
		
		for i = 1 to numThreads do (
			local newWorker = dotnetObject "System.ComponentModel.BackGroundWorker"
			dotNet.addEventHandler newWorker "DoWork" hcMergeTreeFN
			while hcTreeMonitor.occupied do ()
			newWorker.RunWorkerAsync()
		)
		
		hcTreeMonitor.source
	)
	
	fn customAttach source nodes pb:pb1 = 
	(
		count = nodes.count
		
		foo source nodes pb:pb1
	)
 lo1

Interestingly enough, about 60% of the execution time when doing the whole thing with meshes, is the conversion back to poly in the end.

 lo1

I’ve managed to get some scene interaction with background worker, by disabling ref messages.
Perhaps this could be used towards the attach algorithm.

Example:


workers = #()

fn createBox = box()

fn complete s e =
(
	deleteItem workers (findItem workers s)
	if workers.count==0 do enablerefmsgs()
)

disablerefmsgs()

for i = 1 to 8 do
(
	local worker = dotnetObject "System.ComponentModel.BackGroundWorker"
	dotNet.addEventHandler worker "DoWork" createBox
	dotnet.addeventhandler worker "RunWorkerCompleted" complete
	append workers worker	
	worker.RunWorkerAsync()
)

result: 8 boxes created, max doesn’t crash

very cool, I will test this with modifier operations…

 lo1

Seems this is still quite unstable and doesn’t work for all commands.

i think that any max scene change or max UI change can be done in the same as application thread only. that means there is no way to do these operations using multithreading.

Here is a time to show my variant of fast attach. I call it “Caster” (don’t ask me why).
My idea is to have as less as possible number of updates. The ideal algorithm has to attach every time the nodes with minimum number of vertices. So we have to sort the node array every time before attach.
QSORT is very slow if we do it for every iteration of the loop. I’m using .net Sort (sorting second array using first as keys).
Also I don’t use deleteItem (which is also slow for big arrays).
I’m using GetHandleByAnim (to make .net array) and GetAnimByHandle (to speed up access to node’s pointer in an array).

As you can see my algorithm works much faster in situation where we have to attach small boxes to one high-poly box. Without sorting the cluster method has the similar problem as the max Linear method.

check the code and play with parameters…

Here is an optimized version of my version without the multithreading stuff.
It does the same thing Denis’s casterAttach method do but without the need of sorting the array (with or without dotnet’s help) every time and it looks like it works at the same speed if not a bit faster then the caster method.

The idea is taken from the Huffman code algorithm. At first I sort the objects once by vertex count, then I take the first 2 objects in the sorted array, attach them and delete them from the array. Now I use the insertInPlace function to insert a new object created from the 2 attached objects in it’s correct place in the array using a binary search technique. I repeat these steps until the array holds only 1 object. I also make sure I remember which object was originally the source to make sure it doesn’t get deleted.

Anyhow Denis’s method is still very cool and I learned some new stuff from it, tanks for that!

	fn sortByVertNum a b =
	(
		a.val - b.val
	)
	
	struct s_Node (
		obj,
		val,
		isSource = false,
		
		fn init =
		(
			val = obj.numVerts
		),
		
		start = init()
	)
	
	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
		)
	)
	
	fn huffmanAttach source nodes pb:pb1 =
	(
		nodes = for o in nodes collect s_Node obj:o
		append nodes (s_Node obj:source isSource:true)
		qsort nodes sortByVertNum
		local att = polyop.attach
		local n = nodes.count
		
		while nodes.count > 1 do (
			if nodes[2].isSource then
				swap nodes[1] nodes[2]
			att nodes[1].obj nodes[2].obj
			local newNode = s_Node obj:nodes[1].obj isSource:nodes[1].isSource
			deleteItem nodes 2
			deleteItem nodes 1
			insertInPlace nodes newNode start:1 end:nodes.count
			
			pb.value = 100.0 * (1.0 - 1.0 * nodes.count / n)
			verts += newNode.val
		)
	)
	
	fn customAttach source nodes pb:pb1 = 
	(
		count = nodes.count
		
		huffmanAttach source nodes pb:pb1
		
		source
	)

wrong place for the post

Page 5 / 5