Notifications
Clear all

[Closed] Mesh Transform

 MZ1

I see a lot of people use this founction to move vertexes in trimesh:

	fn TransformMesh TheMesh TheTM =
	(
		for i=1 to TheMesh.numverts do
		(
			setvert TheMesh i ((getvert TheMesh i)*TheTM)
		)
		TheMesh
	)

I think Standard transform functions(Move,Rotate,Scale) are much faster than this functuion. This is my compare example:

plugin SimpleObject TestObjects
name:"Door"
classID:#(145345,543411)
category:"TestObjects"
( 
	parameters main rollout:params
	(
		Length type:#worldUnits ui:Length default:0
		Width type:#worldUnits ui:Width default:0
		Height type:#worldUnits ui:Height default:0
		Thickness type:#worldUnits ui:Thickness default:1.6
		DoorsOpen 	type:#float ui:DoorsOpen default:0
	)
	
	rollout params "Parameters"
	(
		spinner Length "Length" type:#worldunits range:[0,1e9,0]
		spinner Width "Width" type:#worldunits range:[0,1e9,0]
		spinner Height "Height" type:#worldunits range:[0,1e9,0]
		spinner Thickness "Thickness" type:#worldunits range:[0,1e9,0]
		spinner DoorsOpen "Open" type:#float range:[0,180,0]
	)
	
	fn TransformMesh TheMesh TheTM =
	(
		for i=1 to TheMesh.numverts do
		(
			setvert TheMesh i ((getvert TheMesh i)*TheTM)
		)
		TheMesh
	)
	
	fn BuildMesh =
	(
		AllMeshes = trimesh()
		
		print "/////////////////////////////////////////"
		
		TS = timestamp()
		for i=1 to 1000 do
		(
			Obj = createInstance box Length:Thickness Width:(Width/2) Height:Height
			Msh = Obj.mesh
			PivotOffset = [Width/4,0,0]
			Msh = move Msh PivotOffset
			Msh = rotate Msh (eulerangles 0 0 -DoorsOpen)
			Msh = move Msh ([Width/4,-Length*i/10,0]-PivotOffset)
			meshop.attach AllMeshes Msh
		)
		format "Standard Transform => %
" ((timestamp()-TS)/1000.0)
		
		TS = timestamp()
		for i=1 to 1000 do
		(
			Obj = createInstance box Length:Thickness Width:(Width/2) Height:Height
			Msh = Obj.mesh
			PivotOffset = [Width/4,0,0]
			TheTM = matrix3 1
			TheTM.row4 = PivotOffset
			TheTM*= rotatezmatrix (-DoorsOpen)
			translate TheTM ([Width/4,-Length*-i/10,0]+(-1*PivotOffset))
			TransformMesh Msh TheTM
			meshop.attach AllMeshes Msh
		)
		format "Vertex Transform => %
" ((timestamp()-TS)/1000.0)
		
		print "/////////////////////////////////////////"
		
		setmesh mesh AllMeshes
		free Msh
		free AllMeshes
	)
	
	on buildMesh do
	(
		BuildMesh()
	)
		
	tool create
	(
		on mousePoint click do
		(
			case click of
			(
				1: nodeTM.translation = gridPoint
				3: #stop
			)
		)
		
		on mouseMove click do
		(
			case click of
			(
				2: (Width = abs gridDist.x; Length = abs gridDist.y)
				3: Height = abs gridDist.z
			)
		)
	)
	
)

13 Replies

Have you tried what the results are if you put the “Vertex Transform” routine before the “Standard Transform” routine?

1 Reply
 MZ1
(@mz1)
Joined: 1 year ago

Posts: 0

Sorry!, my example was not true, just remove or comment a section (reset the max), then test it again:

plugin SimpleObject TestObjects
name:"Door"
classID:#(145345,543411)
category:"TestObjects"
( 
	parameters main rollout:params
	(
		Length type:#worldUnits ui:Length default:0
		Width type:#worldUnits ui:Width default:0
		Height type:#worldUnits ui:Height default:0
		Thickness type:#worldUnits ui:Thickness default:1.6
		DoorsOpen 	type:#float ui:DoorsOpen default:0
	)
	
	rollout params "Parameters"
	(
		spinner Length "Length" type:#worldunits range:[0,1e9,0]
		spinner Width "Width" type:#worldunits range:[0,1e9,0]
		spinner Height "Height" type:#worldunits range:[0,1e9,0]
		spinner Thickness "Thickness" type:#worldunits range:[0,1e9,0]
		spinner DoorsOpen "Open" type:#float range:[0,180,0]
	)
	
	fn TransformMesh TheMesh TheTM =
	(
		for i=1 to TheMesh.numverts do
		(
			setvert TheMesh i ((getvert TheMesh i)*TheTM)
		)
		TheMesh
	)
	
	fn BuildMesh_TM =
	(
		AllMeshes = trimesh()
		
		TS = timestamp()
		for i=1 to 2000 do
		(
			Obj = createInstance box Length:Thickness Width:(Width/2) Height:Height
			Msh = Obj.mesh
			PivotOffset = [Width/4,0,0]
			TheTM = matrix3 1
			TheTM.row4 = PivotOffset
			TheTM*= rotatezmatrix (-DoorsOpen)
			translate TheTM ([Width/4,-Length*-i/10,0]+(-1*PivotOffset))
			TransformMesh Msh TheTM
			meshop.attach AllMeshes Msh
		)
		format "Vertex Transform => %
" ((timestamp()-TS)/1000.0)
		
		setmesh mesh AllMeshes
		free Msh
		free AllMeshes
	)
	
	fn BuildMesh_Standard =
	(
		AllMeshes = trimesh()
		
		TS = timestamp()
		for i=1 to 2000 do
		(
			Obj = createInstance box Length:Thickness Width:(Width/2) Height:Height
			Msh = Obj.mesh
			PivotOffset = [Width/4,0,0]
			Msh = move Msh PivotOffset
			Msh = rotate Msh (eulerangles 0 0 -DoorsOpen)
			Msh = move Msh ([Width/4,-Length*i/10,0]-PivotOffset)
			meshop.attach AllMeshes Msh
		)
		format "Standard Transform => %
" ((timestamp()-TS)/1000.0)
		
		setmesh mesh AllMeshes
		free Msh
		free AllMeshes
	)
	
	on buildMesh do
	(
		BuildMesh_TM()
-- 		BuildMesh_Standard()
	)
		
	tool create
	(
		on mousePoint click do
		(
			case click of
			(
				1: nodeTM.translation = gridPoint
				3: #stop
			)
		)
		
		on mouseMove click do
		(
			case click of
			(
				2: (Width = abs gridDist.x; Length = abs gridDist.y)
				3: Height = abs gridDist.z
			)
		)
	)
	
)




Result for me:

Standard Transform => 0.766
Vertex Transform => 0.953

Now I can say it’s a little faster

first of all it would be faster to calculate destination positions and apply all them as an array

meshop.setVert <Mesh mesh> <vertlist> {<point3 pos> | <point3 pos_array>}

the second is that meshop.attach is a slow function, and if you want to test a ‘transform’ performance don’t combine it with attach

You might need to put gc light:on at the end of the rutine to free the memory.
Sometimes it can be faster to do build the mesh yourself:

plugin SimpleObject TestObjects
  name:"Door"
  classID:#(145345,543411)
  category:"TestObjects"
  ( 
  	parameters main rollout:params
  	(
  		Length type:#worldUnits ui:Length default:0
  		Width type:#worldUnits ui:Width default:0
  		Height type:#worldUnits ui:Height default:0
  		Thickness type:#worldUnits ui:Thickness default:1.6
  		DoorsOpen 	type:#float ui:DoorsOpen default:0
  		ammount type:#integer ui:sp_amount default:2000
  	)
  	
  	rollout params "Parameters"
  	(
  		spinner Length "Length" type:#worldunits range:[0,1e9,0]
  		spinner Width "Width" type:#worldunits range:[0,1e9,0]
  		spinner Height "Height" type:#worldunits range:[0,1e9,0]
  		spinner Thickness "Thickness" type:#worldunits range:[0,1e9,0]
  		spinner DoorsOpen "Open" type:#float range:[0,180,0]
  		spinner sp_amount "Ammount:" type:#integer range:[1,10000,1]
  	)
  
  	on buildMesh do
  	(
  		st = timestamp(); sh = heapfree
  
  		verts  = #()
  		faces  = #()
  
  		masterVerts = #([0,0,0],[1,0,0],[0,1,0],[1,1,0],[0,0,1],[1,0,1],[0,1,1],[1,1,1])
  		matIDs = #()
  		
  		tm = matrix3 1
  		prerotatez tm -doorsopen
  		prescale tm [width/2.0, thickness, height]
  
  		for j = 1 to masterVerts.count do masterVerts[j] *= tm
  		
  		for j = 1 to ammount*8 by 8 do
  		(
  			offset = [0, -length*(j/8)/10.0, 0]
  
  			for i = 1 to 8 do append verts (masterVerts[i]+offset)
  			
  			append faces [j   , j+2 , j+3]
  			append faces [j+3 , j+1 , j  ]
  			append faces [j+4 , j+5 , j+7]
  			append faces [j+7 , j+6 , j+4]
  			append faces [j   , j+1 , j+5]
  			append faces [j+5 , j+4 , j  ]
  			append faces [j+1 , j+3 , j+7]
  			append faces [j+7 , j+5 , j+1]
  			append faces [j+3 , j+2 , j+6]
  			append faces [j+6 , j+7 , j+3]
  			append faces [j+2 , j   , j+4]
  			append faces [j+4 , j+6 , j+2]
  			
  			join matIDs #(2,2,1,1,5,5,4,4,6,6,3,3)
  		 )
  
  		setmesh mesh vertices:verts faces:faces materialIDs:matIDs
  		
  		for j = 1 to mesh.numfaces do
  		(
  			setEdgeVis mesh j 3 false
  			setFaceSmoothGroup mesh j 0
  		)
  		
  		free verts
  		free faces
  		free matIDs
  		
  		gc light:on
  
  		format "time:% ram:%
" (timestamp()-st) (sh-heapfree)
  	)
  		
  	tool create
  	(
  		on mousePoint click do
  		(
  			case click of
  			(
  				1: nodeTM.translation = gridPoint
  				3: #stop
  			)
  		)
  		
  		on mouseMove click do
  		(
  			case click of
  			(
  				2: (Width = abs gridDist.x; Length = abs gridDist.y)
  				3: Height = abs gridDist.z
  			)
  		)
  	)
  	
  )

And it can still be optimized.

it’s faster to make one set of identical faces and clone this time ‘amount’ times.

1 Reply
(@polytools3d)
Joined: 1 year ago

Posts: 0

You mean using meshop.cloneFaces() ? I don’t think so. You still would need to move the vertices.

the bottleneck is not a transforming but an attaching. the attaching would be much faster with using ‘fast’ attach method showed many times on this forum.

it’s an example of my tool works. it paints, resizes, transforms thousands of objects in real-time update

1 Reply
(@polytools3d)
Joined: 1 year ago

Posts: 0

Confirmed! It is faster using the FastAttach() function you wrote.

read the mxs help about meshop.attach … by specifying target or source node you can attach and transform at the same time.

meshop.attach uses AttachMesh MeshDelta method. as an option the relative transform can be specified. i don’t understand why this option is not exposed in mxs directly, but only used when you specify a source or target node

but as i said you can pass any ‘dummy’ node to the attach method to control attaching with a specified transform

delete objects
(
	num = 16
	m = (box()).mesh
	n = mesh vertices:#() faces:#()
	p = point()
	tm = transmatrix [100,0,0]
		
	for k=0 to num-1 do
	(
		p.transform = tm
		meshop.attach n.mesh (copy m) targetnode:p
		tm = prerotateZ tm (360.0/num)
	)
	update m
)

or using source (which is more correct):

delete objects
(
	num = 16
	m = (box()).mesh
	n = mesh vertices:#() faces:#()
	p = point()
	tm = transmatrix [100,0,0]
		
	for k=0 to num-1 do
	(
		p.transform = inverse tm
		meshop.attach n.mesh (copy m) [B]sourcenode:p deletesourcenode:off[/B]
		tm = prerotateZ tm (360.0/num)
	)
	update m
)
Page 1 / 2