Unwrap moveselected undo

Hello. I have two related problems with Unwrap moveselected functions. Actually I need rotate and scale as well, but to simplify my question I will talk only about move.

There are two move functions in Unwrap: moveSelected and moveSelectedVertices.
Problem with moveSelected.
It eats a RAM on big meshes, maybe because of Undo stack, but it does that even with Undo off. And if undo is on, then it creates only 1 record.

fn moveVerts = with undo "Move verts" off (
	unw = modPanel.getCurrentObject()
	for i=1 to 100 do (
		unw.selectVertices #{i}
		unw.moveSelected [0.1,0.1,0]
	)
)
moveVerts()

Each iteration of this function will eat ~150MB of RAM and it doesn't even create Undo record. gc() doesn't help. That's why I ended up with next function.
_________________________________________

Problem with moveSelectedVertices.
I can't enable undo record. I tried theHold also.

fn moveVerts = with undo "Move verts" on (
	unw = modPanel.getCurrentObject()
	for i=1 to 100 do (
		unw.selectVertices #{i}
		unw.moveSelectedVertices [0.1,0.1,0]
	)
)
moveVerts()

So this function won't eat memory at all. But it doesn't create undo record.
_________________________________________

And I need function that creates 1 undo record and doesn't eat much ram :)

P.S. Is it a bug with memory leak in moveSelected?

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
NiK684's picture

So when I'm trying to parse

So when I'm trying to parse 10k polygons in this plane then 3dsmax eats 20gigs :)

And when I'm dealing with "moveSelectedVertices" 3dsmax doesn't eat ram at all. And actually it's a little faster in my case.
But even theHold can't undo UV transformations with "moveSelectedVertices" :( It creates undo record but undoing doesn't revert changes.

(
	fn randomizeFacesOnce bits = (
 
		unw = modPanel.getCurrentObject()
		_mode = unw.getTVSubObjectMode()
		unw.setTVSubObjectMode 1
		unw.selectVertices bits
		unw.moveSelectedVertices [random 0.0 1.0 , random 0.0 1.0 , 0]
		unw.rotateSelectedVerticesCenter (random 0.0 360.0)
		unw.scaleSelectedVerticesCenter (random 0.5 1.5) 0
 
		if _mode != 1 do unw.setTVSubObjectMode 1
	)
 
	theHold.Accept()
	theHold.Begin()
	for i=1 to 1000 do randomizeFacesOnce #{i}
	theHold.Accept "1000 Unwrap moves"
)

Here you go. This changes cannot be undone. Maybe this is the reason why it doesn't eat memory :)

jahman's picture

.

actually we can trick it with single moveSelected call (which is creating Undo record)

(
	delete objects
	g = plane widthsegments:100 lengthsegments:100
	convertToPoly g
	select g;
	max modify mode
	subobjectlevel = 2
	polyop.setEdgeSelection g #all
	g.EditablePoly.splitEdges()
	addModifier g (uvwmap maptype:5)
	addModifier g (Unwrap_UVW())
 
	gc();t1=timestamp();hf = heapfree
 
	unw = modPanel.getCurrentObject()
	bits=#{}
 
	movSel = unw.moveSelectedVertices 
	rotSel = unw.rotateSelectedVerticesCenter 
	sclSel = unw.scaleSelectedVerticesCenter
	face2vert = unw.faceToVertSelect
 
	theHold.Accept()
	theHold.Begin()
	unw.selectFaces #{1}
	unw.moveSelected [0,0,0]
 
 
	for i=1 to 4000 do (
 
		bits = #{i}
 
		unw.selectFaces bits
		unw.faceToVertSelect()
 
		movSel [random 0.0 1.0 , random 0.0 1.0 , 0] 
		rotSel (random 0.0 360.0)
		sclSel (random 0.5 1.5) 0		
 
	)
 
	theHold.Accept "4000 Unwrap moves"	
	format "randomizeFaces      Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 )
NiK684's picture

But I'm still curious why

But I'm still curious why moveselected needs so much memory compared to moveselectedvertices.
Can you confirm that?

NiK684's picture

This trick did the

This trick did the job!

Спасибо в очередной раз :)

NiK684's picture

I tested it more. It seems

I tested it more. It seems 1000-4000 operations with unwrap transforms should eat some gigs of ram for Undo stack. When I'm talk about ram eating I mean 3dsmax ram consumption in TaskMakager.
I used incorrect terminology when I said that script eat this ram. Not script, 3dsmax itself.

Here is a bigass plane and 4000 operations. 3dmsax eats ~3-4GB after this. And I suppose this ram consumes mainly for undo because gc() can clean it.

(
	delete objects
	g = plane widthsegments:100 lengthsegments:100
	convertToPoly g
	polyop.setEdgeSelection g #all
	g.EditablePoly.splitEdges()
	addModifier g (Unwrap_UVW())
 
	select g;
	max modify mode
 
 
	gc();t1=timestamp();hf = heapfree
	theHold.Accept()
	theHold.Begin()
 
	for i=1 to 4000 do (
		bits=#{i}
		unw = modPanel.getCurrentObject()
		_mode = unw.getTVSubObjectMode()
		unw.setTVSubObjectMode 3
		unw.selectPolygonsUpdate bits false
		unw.moveSelected [random 0.0 1.0 , random 0.0 1.0 , 0] 
		unw.rotateSelectedCenter (random 0.0 360.0)
		unw.scaleSelectedCenter (random 0.5 1.5) 0
		if _mode != 3 do unw.setTVSubObjectMode 3
	)
	theHold.Accept "4000 Unwrap moves"	
	format "randomizeFaces      Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 )

So... it seems there is no leaks, there is no bugs, 3dsmax should eat that gigs for such operations?

jahman's picture

.

What's the point in moving verts one by one? :)
All of the below examples create "MaxScript" Undo entry, but wipe out previous undo stack entirely.
I'd like to know how this behavior can be prevented too.

btw. if you place theHold.Accept() before function call you'll have a correct Undo entry name as a result.

(
fn moveVertsOneByOne bits = with undo "Move verts" on (
 
	unw = modPanel.getCurrentObject()
 
	for i in bits do (
		unw.selectVertices #{i}
		unw.moveSelected [0.1,0.1,0]
	)
)
 
fn moveVertsOnce bits = with undo "Move all verts" on (
 
	unw = modPanel.getCurrentObject()	
	unw.selectVertices bits
	unw.moveSelected [0.1,0.1,0]
 
)
 
 
fn moveVertsOnce2 bits = with undo "Move all verts 2" on (
 
	unw = modPanel.getCurrentObject()	
	unw.selectVertices bits
	unw.moveSelectedVertices [0.1,0.1,0]
 
)
 
 
delete objects
g = convertToMesh (geosphere segments:20)
addModifier g (Unwrap_UVW())
select g;
max modify mode
 
gc();t1=timestamp();hf = heapfree
 
	moveVertsOneByOne #{1..2500}
 
 
format "moveVertsOneByOne Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 
 
 
gc();t1=timestamp();hf = heapfree
 
 
	moveVertsOnce #{1..2500}
 
 
format "moveVertsOnce     Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 
 
gc();t1=timestamp();hf = heapfree
 
	moveVertsOnce2 #{1..2500}
 
format "moveVertsOnce2    Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 
 
)


moveVertsOneByOne Time: 1.444sec. Mem: 162184L
moveVertsOnce Time: 0.001sec. Mem: 704L
moveVertsOnce2 Time: 0.001sec. Mem: 632L

NiK684's picture

"What's the point in moving

"What's the point in moving verts one by one? :)"

Forgot to mention. That piece of code is just for demo of course :) Just to reduce strings. My script parse elements and select whole elements, not verts one by one.

Anyway. At first I used "moveSelected" and faces, not vertices. But this function somehow leaks memory very dramatically. But it created undo record.

Then I found that "moveSelectedVertices" doesn't leak ram and I was happy until I realised that I can't undo it.

jahman's picture

.

I use max2014 and can't confirm any of the issues you're talking about.
Here's 800k faces geoSphere. Can you post your results for this one?

(
 
fn moveFacesOnce bits = with undo "Move all faces" on (
 
	unw = modPanel.getCurrentObject()
	_mode = unw.getTVSubObjectMode()
	unw.setTVSubObjectMode 3
	unw.selectFaces bits
	unw.moveSelected [0.5,0.5,0]
 
	if _mode != 3 do unw.setTVSubObjectMode 3
 
)
 
 
delete objects
g = convertToMesh (geosphere segments:200)
addModifier g (Unwrap_UVW())
select g;
max modify mode
 
 
gc();t1=timestamp();hf = heapfree
 
	theHold.Accept() -- that's a bad idea in general. 
	moveFacesOnce #{1..(meshop.getNumMapFaces g 1)}
 
format "moveFacesOnce     Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 
 
)

moveFacesOnce Time: 0.291sec. Mem: 1024L

NiK684's picture

max2016 - moveFacesOnce

max2016 - moveFacesOnce Time: 0.182sec. Mem: 6184L
But my case is different. I need to randomize some array of UV faces bitarrays.
Select each bitarray of faces and then randomize it. Speed is not impressive but okay.
I'll explain it other way.

I have a test mesh that contains 2500 attached boxes. Next code will randomize offset on first (for example) 3000 faces. My task is not exactly like this, this is only general idea.

unw = modPanel.getCurrentObject()
for i=1 to 3000 do (
	unw.selectPolygonsUpdate #{i} false
	ofst = [random 0.0 1.0 , random 0.0 1.0 , 0]
	unw.moveSelected ofst
)

This script takes 4GB ram. I'm not sure why, because undo record is only one.

jahman's picture

.

Nope, can't confirm. Some test scene would be great tho.

randomizeFacesOnce Time: 1.369sec. Mem: 8256L

(
 
fn randomizeFacesOnce bits = (
 
	unw = modPanel.getCurrentObject()
	_mode = unw.getTVSubObjectMode()
	unw.setTVSubObjectMode 3
	unw.selectFaces bits
	unw.moveSelected [random 0.0 1.0 , random 0.0 1.0 , 0]
	unw.rotateSelectedCenter (random 0.0 360.0)
	unw.scaleSelectedCenter (random 0.5 1.5) 0
 
	if _mode != 3 do unw.setTVSubObjectMode 3
 
)
 
 
delete objects
g = plane widthsegments:10 lengthsegments:10
convertToPoly g
g.EditablePoly.SetSelection #Edge #{1..220}
g.EditablePoly.splitEdges ()
addModifier g (TurboSmooth iterations:5)
addModifier g (Unwrap_UVW())

select g;
max modify mode
 
 
gc();t1=timestamp();hf = heapfree
 
	theHold.Accept()
	theHold.Begin()
	step = int ((meshop.getNumMapFaces g 1)/100)
	for i=0 to 99 by 2 do (
 
		randomizeFacesOnce #{(1 + i*step)..(i*step + step)}
 
	)
	theHold.Accept "100 Unwrap moves"
 
format "randomizeFacesOnce      Time: %sec. Mem: %\n" ((timestamp()-t1)/1000 as float) (hf-heapfree)
 
 
)

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.