Detach script with c ++

Detach script with c ++

anycganycgJ8A6A
Advocate Advocate
4,025 Views
44 Replies
Message 1 of 45

Detach script with c ++

anycganycgJ8A6A
Advocate
Advocate

hi

Nice to meet you

I have a problem

I have a 5000 object

That is attached..

I would like to detach with elements

I tested many detahel script

But all is failed or max freezz problem

So i found this link

 

C++ detach script

 

https://forums.cgsociety.org/t/c-detach-by-elements/1707338

 

If i use c++ , can i detach my objects

 

I dont know c++

 

Uf that is possible , can you help that ?

0 Likes
Accepted solutions (1)
4,026 Views
44 Replies
Replies (44)
Message 21 of 45

anycganycgJ8A6A
Advocate
Advocate
hi denist
thank you for good code
i tested this code
gettempmesh type error : call needs function or class got : undefined
i tested that in 3d max 2017 and 2022
sorry for many ask
0 Likes
Message 22 of 45

denisT.MaxDoctor
Advisor
Advisor

@anycganycgJ8A6A wrote:

gettempmesh type error : call needs function or class got : undefined


Ouch! gettempmesh is my function, I forgot. Just replace gettempmesh with snapshotasmesh.

0 Likes
Message 23 of 45

anycganycgJ8A6A
Advocate
Advocate
Tested
Wow wow perpect perpect
Very good very good
I love this script
1. Speed is good
2. Group option is very nice
3. It's good that max program doesn't freeze

Wow wow wow
Really really thank you
0 Likes
Message 24 of 45

miauuuu
Collaborator
Collaborator

The scene, provided by the OP, with 48600 elements, detach all elements as separate objects

- original code by Denis -> 1534 s

- removed statistic, debugging, etc. - 1251 s

 

Denis, if you have C++ code which does the same can you share how fast it is compared to the mxs?

 

P.S. this

gettempmesh

is not defined, so I replaced it with snapshotAsMesh

"

https://miauu-maxscript.com/
0 Likes
Message 25 of 45

denisT.MaxDoctor
Advisor
Advisor

@miauuuu wrote:

The scene, provided by the OP, with 48600 elements, detach all elements as separate objects

- original code by Denis -> 1534 s

- removed statistic, debugging, etc. - 1251 s

 

Denis, if you have C++ code which does the same can you share how fast it is compared to the mxs?

 


Now I have preliminary results for C++ for the above example...

now it takes ~12s (only detaching meshes without creating nodes)

I think I can improve the algorithm and cut the time by at least half.

Message 26 of 45

anycganycgJ8A6A
Advocate
Advocate
Wow wow ~12s ?
Are you friendly with aliens?
0 Likes
Message 27 of 45

denisT.MaxDoctor
Advisor
Advisor

@miauuuu wrote:

The scene, provided by the OP, with 48600 elements, detach all elements as separate objects

- original code by Denis -> 1534 s

- removed statistic, debugging, etc. - 1251 s

1251s is a big number ... it's 21 min ... it's too much even for MXS.
I hope to make it 3-4 min. This will be a good result.

0 Likes
Message 28 of 45

denisT.MaxDoctor
Advisor
Advisor

the main difference between the algorithms for MXS and c++ is the ability in the second case to use an almost unlimited amount of memory to create intermediate structures .... in MXS, working with memory is a serious obstacle ... it's both slow and very limited

0 Likes
Message 29 of 45

denisT.MaxDoctor
Advisor
Advisor
Accepted solution

here is the new script... it does all the detached meshes in 80 seconds on my machine, but it takes longer to create the nodes... and for some unknown reason, the creation time is very long on my laptop (which I currently use while traveling).

It takes about 3 minutes to build all the detached elements on my machine for the above example. 

 

try(destroydialog TakeApartRecurseRol) catch()
rollout TakeApartRecurseRol "Take Apart Recursive" width:191
(
	fn memoryStatus = (int (100 * heapFree / heapSize))

	fn splitMeshInHalf mesh temp:#() done:#() faces: detach:on pb: = if iskindof mesh TriMesh and mesh.numfaces > 0 do 
	(
		local _detachfaces = meshop.detachfaces
		
		local t0 = timestamp()

		local numfaces = mesh.numfaces
		local numverts = mesh.numverts
		
		local allfaces = #{1..numfaces}
		local verts = for v = 1 to numverts collect #()
		
		for j in allfaces do
		(
			f = getface mesh j
			for k = 1 to 3 do append verts[f[k]] j
		)
		
		local out = false
		local element = #()
		if faces == unsupplied do faces = allfaces
					
		local elements = #{}
		local num_elements = 0
		
		for i in faces while not out and not keyboard.escPressed do
		(
			element = #(i)
			for j in element where faces[j] do
			(
				faces[j] = false
				f = getface mesh j
				for k = 1 to 3 where verts[f[k]] != undefined do
				(
					join element verts[f[k]]
					verts[f[k]] = undefined
				)
			)
			
			element = makeuniquearray element
			
			if (elements.numberset + element.count >= numfaces/2) then out = true
			else
			(
				for i in element do append elements i
				num_elements += 1
			)
		)
		
		if num_elements == 0 do
		(
			for i in element do append elements i
			num_elements += 1
		)
		
		donefaces = 0
		if (elements.numberset < numfaces) then
		(
			half = _detachfaces mesh elements delete:true asmesh:true
			if (num_elements == 1) then 
			(
				append done half
				donefaces = half.numfaces
			)
			else append temp half
			--update mesh
		)
		else
		(
			if (k = finditem temp mesh) > 0 do deleteitem temp k
			append done mesh
			donefaces = mesh.numfaces
		)

		free verts
		
		donefaces
	)	
	
	
	label facetype_lb "Use Face: " align:#left offset:[0,4] across:2
	radiobuttons facetype_rb labels:#("All", "Selected") columns:2 align:#left offset:[-28,3] offsets:#([0,0],[-13,0]) enabled:off

	checkbox recurse_ch " Recursive" checked:on align:#left offset:[0,4] enabled:off across:2
	checkbox detach_ch " Detach" align:#left offset:[11,4] 

	checkbutton mxs_detach_bt "MXS Process" highlightcolor:orange width:172 align:#left offset:[-4,2] 
	progressbar progress_pb color:orange width:172 height:8 align:#center offset:[0,0]
	
	group "Statistics: "
	(
		checkbox curr_cb " All Elements" checked:on align:#left offset:[10,0] across:3
		label info_01 "0" align:#right offset:[40,0]
		label data_01 "" width:20 align:#right offset:[8,0]
		checkbox mesh_cb " Element nodes" checked:on align:#left offset:[10,0] across:3
		label info_02 "0" align:#right offset:[40,0]
		label data_02 "" width:20 align:#right offset:[8,0]
		checkbox time_cb " Time" checked:on align:#left offset:[10,0] across:3
		label info_03 "0" align:#right offset:[40,0]
		label data_03 "s" width:20 align:#right offset:[8,0]
		checkbox heap_cb " Memory" checked:on align:#left offset:[10,0] across:3
		label info_04 "0" align:#right offset:[40,0]
		label data_04 "%" width:20 align:#right offset:[8,0]
	)
	group "Settings and Debug: "
	(
		checkbox debugh_ch " Debug" align:#left offset:[0,4] across:2 enabled:off
		checkbox gclight_ch " GC Light" align:#left offset:[11,4]
		button gc_bt "Garbage Collection" width:172 align:#left offset:[-4,2] 
	)
		
	fn memoryDisplay = 
	(
		info_04.text = memoryStatus() as string
	)
	on gc_bt pressed do 
	(
		gc light:gclight_ch.state
		memoryDisplay()
		completeRedraw()
	)
	
	local num
	local t0, t1
	local h0, h1

	on mxs_detach_bt changed state do if state do undo "Detach" off, with redraw off
	(
		node = selection[1]
		if iskindof node GeometryClass do
		(
			gc light:on
			memoryDisplay()
			
			t0 = timestamp()
			h0 = heapfree
			
			mesh = snapshotasmesh node
			numfaces = mesh.numfaces
			donefaces = 0
			progress_pb.value = 0
			progress_pb.color = orange
			factor = 100./numfaces
			windows.processPostedMessages()
			
			faces = if facetype_rb.state == 1 then #{1..mesh.numfaces} else (mesh.selectedfaces as bitarray)
			
			done = #()
			temp = #(mesh)
			data = #(0,0,0,0)
			
			while temp.count > 0 and not keyboard.escPressed and mxs_detach_bt.state do
			(
				count = temp.count
				mesh = temp[1]
				
				if curr_cb.state do 
				(
					v = temp.count
					if data[1] != v do info_01.text = (data[1] = v) as string
				)

				donefaces += splitMeshInHalf mesh temp:temp done:done detach:on 
				progress_pb.value = donefaces * factor
				
				if curr_cb.state do 
				(
					v = temp.count
					if data[1] != v do info_01.text = (data[1] = v) as string
				)
				if mesh_cb.state do 
				(
					v = done.count
					if data[2] != v do info_02.text = (data[2] = v) as string
				)
				if time_cb.state do 
				(
					v = (timestamp() - t0) / 1000
					if data[3] != v do info_03.text = (data[3] = v) as string
				)
				if heap_cb.state do 
				(
					v = memoryStatus()
					if data[4] != v do info_04.text = (data[4] = v) as string
				)
				
				windows.processPostedMessages()
			)
			
			info_01.text = temp.count as string
			info_02.text = done.count as string
			info_03.text = ((timestamp() - t0) / 1000) as string
			info_04.text = memoryStatus() as string
			
			global _et = temp
			global _ed = done
			
			t1 = timestamp()
			h1 = heapfree
			
			format "DETACH ... count:% time:% heap:%\n" done.count (t1 - t0) (h0 - h1)
			
			if detach_ch.state do if temp.count == 0 do with redraw off
			(
				t2 = timestamp()
				h2 = heapfree
			
				max create mode
				
				progress_pb.value = 0
				progress_pb.color = green
				factor = 100./done.count
				windows.processPostedMessages()
				
				prefix = node.name + "_"
				
				parts = for k = 1 to done.count while not keyboard.escPressed and mxs_detach_bt.state collect
				(
					m = done[k]
					name = uniquename prefix
					n = editable_mesh name:name parent:node
					n.mesh = m
					progress_pb.value = k * factor
					windows.processPostedMessages()
					n
				)
				
				t3 = timestamp()
				h3 = heapfree
				
				format "CREATE ... count:% time:% heap:%\n" parts.count (t3 - t2) (h2 - h3)
				
				completeredraw()
			)
		)
		
		mxs_detach_bt.state = off
	)


	on TakeApartRecurseRol open do
	(
		gc light:on
		memoryDisplay()
	)
)
createdialog TakeApartRecurseRol

 

What are your numbers?

0 Likes
Message 30 of 45

denisT.MaxDoctor
Advisor
Advisor

I'm pretty sure it's possible to make the mesh detach about twice as fast... I see some optimizations, but that's a challenge for someone else. For me the task is done.

 

0 Likes
Message 31 of 45

anycganycgJ8A6A
Advocate
Advocate
Really Thank you so much for your hard work during the trip. I will test
0 Likes
Message 32 of 45

anycganycgJ8A6A
Advocate
Advocate
I test
Max 2014 : 150s
Max 2017 : 216s
Max 2022 : 160s

Very fast ~~
0 Likes
Message 33 of 45

anycganycgJ8A6A
Advocate
Advocate
I test 10,000 objects
Time is 20s
Crate node is fast also
0 Likes
Message 34 of 45

Serejah
Advocate
Advocate

for some reason second version is times slower
tested in 2014 & 2020. 2020 is x2 slower ( 312sec ) 🤔
v1 timings:
count:0 time:8441 heap:30471558L

v2 timings:
DETACH ... count:168 time:121759 heap:16171272L
CREATE ... count:168 time:528 heap:176392L

Serejah_0-1660974683154.png

 

0 Likes
Message 35 of 45

istan
Advisor
Advisor
some remarks from my side:
- C++ will be a lot faster (I can't distribute the code, as it's part of my application)
- Undo ?
- I have scripts, where I had to remove 'windows.processPostedMessages()' again, as they produced extra delays. I never found out under which circumstances.
Message 36 of 45

denisT.MaxDoctor
Advisor
Advisor

@Serejah wrote:

for some reason second version is times slower
tested in 2014 only
v1 timings:
count:0 time:8441 heap:30471558L

v2 timings:
DETACH ... count:168 time:121759 heap:16171272L
CREATE ... count:168 time:528 heap:176392L

 


tested in 2014 only ... the difference.

 

max 2014 and max 2019+ have different maxscript memory management system. 2019+ is much faster does garbage collection and memory freeing. Both versions have very serious memory leaks for large bitarrays. I can probably guess where we lose performance in the 2014 version, but as of recently, I no longer work and test this version.

Message 37 of 45

denisT.MaxDoctor
Advisor
Advisor

@istan wrote:
some remarks from my side:
- C++ will be a lot faster (I can't distribute the code, as it's part of my application)
- Undo ?
- I have scripts, where I had to remove 'windows.processPostedMessages()' again, as they produced extra delays. I never found out under which circumstances.

how fast is your c++ version to break the test example mesh of element meshes?

Message 38 of 45

istan
Advisor
Advisor
Sorry, but I currently do not have time to test. I use MXS only for quick prototyping or user customization but always end up with C++. From my experience there's always a factor 2..50 between.
Istan
PS: I even made friends with QT on a daily use 😉
0 Likes
Message 39 of 45

denisT.MaxDoctor
Advisor
Advisor

By the way, check your methods when you have time... I also lived, did not grieve with my algorithms, which were fast enough...
Until I met this special case.

The thing is, this mesh has a huge amount of small elements, and they are probably made with Extrude and Cap. Thus, each element has faces with lower and upper indexes, which creates the worst situation for BitArrays.
Finally, I had to heavily rewrite the part of the code responsible for finding mesh elements. What gave me a 4 times increase in search speed (!)
Now it takes 7 seconds to divide this whole example mesh into separate mesh elements. (80 sec for MXS).

0 Likes
Message 40 of 45

istan
Advisor
Advisor
Hi Denis,
Ok. Afair the original algorithm finds elements based on adjacent edges.
..and you confirmed my factor 😉
0 Likes