Notifications
Clear all

[Closed] Fastest Way to grab every Nth Face from multiple meshes….?

So I some really basic code which takes every nth face from a bunch of objects and creates a new proxy mesh. Doesn’t do a particularly good job with normals, but that’s not really a priority… Works for simple scenes but slow as hell on a large face/object count and doesn’t work with a Teapot Primitive but I can’t work out why… Think I need to start again

fn makeFaceShape node =
(
	vert_array = #() --array of vertices positions
	face_array = #() --array of vertices to use to make face
	vert_count = 0
	
	for n in join #() node do
	(
		for i = 1 to meshop.getnumfaces n.mesh by 40 do
		(
			verts = meshop.getVertsUsingFace n.mesh #{i}
			if verts.count > 3 do
			(
				for v in verts do
				(
					append vert_array (n.mesh.vertices[v].pos + n.pos)
				)
				append face_array [vert_count+1,vert_count+3,vert_count+2]
				vert_count += 3

			)
		)
	)
	m = mesh vertices:vert_array faces:face_array
	select m
)

makeFaceShape $
16 Replies

Hi David,
Here is a different approach that might work for what you need. I don’t know if you would also need to attach all the resulting proxies.

fn makeFaceShape node interval:40 =
    (
    	m = snapshotasmesh node
    	faces = m.faces as bitarray
    	for j = 1 to m.numfaces by interval do faces[j] = false
    
    	meshop.deletefaces m faces
    	m = mesh mesh:m
    	select m
    )
For a 40 segments teapot (100K Tris) I got these results:
time:1906 ram:2796104L 
time:74 ram:1512L

And without the “select m” line:
time:1833 ram:2794856L
time:9 ram:1512L

Hmm I’m wondering on a particuarly heavy scene whether a snapshot as mesh would be too heavy, and would it be better to build rather than start with a mesh and remove.

My code will take a collection of nodes and proxy all children as well, which is important, and yes it needs to be one mesh

OK, here is a slightly optimized version of your function:

fn MakeFaceShape nodes interval:40 =
      (
      	vert_array = #()
      	face_array = #()
      	vert_count = 0
      	
      	for n in nodes do
      	(
      		m = snapshotasmesh n
      		
      		for i = 1 to m.numfaces by interval do
      		(
      			verts = getface m i
      			for v = 1 to 3 do append vert_array (getvert m verts[v])
      			append face_array [vert_count+1,vert_count+2,vert_count+3]
      			vert_count += 3
      		)
      	)
      	mesh vertices:vert_array faces:face_array
       )

32 objects 2 million Tris:
time:24600 ram:14177112L
time:210 ram:16345896L

128 objects 8 million Tris:
time:860 ram:65271144L

i think that will be more correct to continue incomplete ‘interval’ with next node. that means if we have 100 one-face nodes and interval equals 40 we will get only 2 faces from them instead of 100 as we get now.

fn pickfaces nodes step:10 =   
 (
 	faces = #()
 	left = 0
 	for node in nodes where iskindof node GeometryClass do 
 	(
 		mesh = snapshotasmesh node
 		for k = left + 1 to mesh.numfaces by step do append faces (k as integer) --<getface mesh k>
 		left = mod (mesh.numfaces - left) step
 		free mesh
 	)
 	faces 
 ) 

But DenisT, what happens when your number of faces is less than your left value

mod (-5) 20

And we must add protection for those pesky TargetObjects which are geometryClass.

for node in nodes where iskindof node GeometryClass and classof n != Targetobject do 
4 Replies
(@denist)
Joined: 11 months ago

Posts: 0

or just

canconvertto node Editable_Mesh
(@davewortley)
Joined: 11 months ago

Posts: 0

Damn, every time I think I’ve got one up on you Denis you always out-smart me

(@polytools3d)
Joined: 11 months ago

Posts: 0

Oh yes, error checking as well as assigning local variables are missing in the code.

Also you might want to consider checking the HeapSize if you are working with huge scenes, as the dynamic allocation is very slow.

Less than a second to process 8 million Tris is not too bad for a scripted solution, but is you need to save memory you could use SetFace and SetVert instead of storing the values in an array. It will be slower but will use much less memory.

Another thing that could be done is to calculate the amount of faces per node based on a percentage of the total faces areas, so small objects with large amount of faces would get similar details to large objects with small number of faces. But I don’t know if it is a concern for you.

(@davewortley)
Joined: 11 months ago

Posts: 0

Yeah it seems fairly fast at the moment, I’ve made my own function with a mix of mine, yours and Denis’s ideas, and I’ve made a version for doing the same with vertices as well.

honestly i didn’t try what i wrote. because i didn’t have max at that time.

I thought that SetVert and SetFace would make it much slower, but changing a few other things in the function, it Works much faster.

For the 128 objects and 8 million Tris, it was around 30% faster and used 6 times less memory.

Pushing it further here is a comparison with the previous function for 10K Objects 100 Million Tris:

time:427958 ram:407063224L
time:7611 ram:146140672L

fn BuildProxyMeshFromNodes nodes interval:40 =
  (
  
  	fn ValidateNodes nodes =
  	(
  		for node in nodes where iskindof node geometryclass and canconvertto node editable_mesh collect node
  	)
  	
  	nodes = ValidateNodes nodes
  	numfaces = 0
  	lastvert = 0
  
  	for node in nodes do numfaces += node.mesh.numfaces
  
  	proxy = trimesh()
  	setmesh proxy numverts:((numfaces/interval)*3) numfaces:(numfaces/interval)
  
  	for node in nodes do
  	(
  		
  		m = snapshotasmesh node
  		
  		for i = 1 to m.numfaces-interval by interval do
  		(
  			verts = getface m i
  			
  			v1 = lastvert+1
  			v2 = lastvert+2
  			v3 = lastvert+3
  			
  			setvert proxy v1 (getvert m verts.x)
  			setvert proxy v2 (getvert m verts.y)
  			setvert proxy v3 (getvert m verts.z)
  			
  			setface proxy (v3/3) v1 v2 v3
  
  			lastvert += 3
  		)
  		
  		free m
  		
  	)
  	
  	mesh mesh:proxy
  )

Nice one.
I reorganized your code a bit.
Can you check if this have any impact on performance?


 fn BuildProxyMeshFromNodes nodes interval:40 =
 (
 	array = #() ; number = 0
 	for node in nodes where canconvertto node editable_mesh do
 	(
 		node = snapshotasmesh node
 		append array node
 		number += node.numfaces
 	)
 	if array.count == 0 then return false else
 	(
 		value = 0
 		proxy = trimesh()
 		setmesh proxy numverts:((number/interval)*3) numfaces:(number/interval)
 		
 		for m in array do
 		(
 			for i = 1 to m.numfaces-interval by interval do
 			(
 				verts = getface m i
 				v1 = value+1
 				v2 = value+2
 				v3 = value+3
 				setvert proxy v1 (getvert m verts.x)
 				setvert proxy v2 (getvert m verts.y)
 				setvert proxy v3 (getvert m verts.z)
 				setface proxy (v3/3) v1 v2 v3
 				value += 3
 			)
 			free m			
 		) ; free array
 		mesh mesh:proxy
 	)
 )
 
Page 1 / 2