Retopology from the UV mesh


#35

It could be, but I am afraid the final user may not know how to verify both meshes, unless he/she implements another code to measure the meshes areas.

In my opinion, the best way to verify if the meshes have the same (or similar) scale is to measure both surfaces areas.

The code I added in the version 0.5 does this; just scale the uvw mesh to match the geometry mesh. I can’t see a situation where this method would be less accurate than the others.

These are the issues with the methods described so far:

#Arbitrary edge length
Vertex indices are not the same between geo and uvw meshes
Even if vertices are the same, the edge could be highly distorted compared with the other edges

#Arbitrary face area
Face could be highly distorted compared with the other faces


#36

The scale of “flat” object need to be approximately exact but not perfectly exac.
Why? Because this object will be reference for newly retopologized object. When scale is similar user can easily decide which size of quad need to be used for retopology process.


#37

But why use a method that we already know can fail when there is another that is more accurate and does not have any drawbacks?


#38

On which method you referring?


#39

This one I added in v 0.5 (http://forums.cgsociety.org/showpost.php?p=7753370&postcount=31) Which uses the total object surface area to scale the UVW Mesh

uvwarea = meshop.getfacearea m1 #{1..m1.numfaces}
   factor = sqrt (geoarea/uvwarea)
   scale m1 [factor,factor,0]

#40

Here is a test case. After running it use version 0.4 and 0.5 of the UVW Mesh script to get the uvw mesh using the Real Scale option.

v0.4 - Uses arbitrary edge length
v0.5 - Uses geometry surface area

(
 delete objects
 node = converttopoly (teapot isSelected:true)
 
 uvwmod = unwrap_uvw()
 modpanel.addmodtoselection uvwmod ui:on
 
 uvwmod.flattenmap 60.0 #() 0.01 true 0 false true
 )

#41

looking at your development process i found helpful make this function for you:

fn uvToMesh node channel:1 scaleFactor:1.0 = 
(
	_mesh = snapshotasmesh node
	sc = point3 scaleFactor scaleFactor scaleFactor
	verts = for v=1 to meshop.getnummapverts _mesh channel collect (meshop.getmapvert _mesh channel v)*sc
	faces = for f=1 to meshop.getnummapfaces _mesh channel collect meshop.getmapface _mesh channel f
		
	mesh name:(node.name + "_uvmesh") vertices:verts faces:faces	
)

delete objects

b = box()
modi = Unwrap_UVW()
addmodifier b modi
max modify mode
select b
modpanel.setcurrentobject modi
modi.flattenMapNoParams()
max create mode
clearselection()
addmodifier b (tessellate tension:0 iterations:3)
addmodifier b (tessellate tension:0 iterations:1)
gc light:on
	

t1 = timestamp()
uvToMesh b scaleFactor:100.0
format "verts:% time:%
" b.numverts (timestamp()-t1)

edited… i’ve added tessellation just to show how fast it is. and of course the function need some standard optimization steps and a fool-proofing.


#42

Ice-boy sended me this file for test (max2011 file).
Denis your code breaks down model into small pieces.
Jorge already have nice and clean solution.


#43

That’s another way of doing the same thing (almost). The performance on my end is around 25% faster and it uses around 6 times more memory for your test box.
faces:49152 time:96 memory:9567184L
faces:49152 time:118 memory:1652344L

For larger meshes the speed is almost the same but it still uses 6 times more memory
faces:196608 time:1155 memory:37990640L
faces:196608 time:1209 memory:6420120L

So, it does not have a substantial improving regarding speed and it uses much more memory.

Other issues I see are that the output mesh is triangulated, and its mapping if offset.

It also lacks the option to split your source mesh based on the different uv shells, which was the main purpose of my script.


#44

it doesn’t brake anything.

@Jorge: put meshop functions in my function into locals. as usually i do it. it saves the memory.


#45

Just use it on the file that I posted, also disable tessallate modifier


#46

If I do so, it would no longer be a cute 5 lines code :slight_smile:
Anyway, while speed and memroy ussage are pretty similar, the other two issues still remains (triangulation and uvw map shift).


#47

according my tests my function works ~3 times faster… memory… yes. it uses. because it makes arrays.


#48

it doesn’t do anything with triangulation… about uv map i just don’t care and do nothing. but it’s very easy to fix


#49

I wonder… The results on my tests are as I previously mentioned. I suppose you are testing both functions together (mine first) without rebuilding the whole test case.

In that case the function you test at last, will appear to be faster. But try the following test and put back your result please.

(
  	
  	fn uvToMesh node channel:1 scaleFactor:1.0 = 
  	(
  		_mesh = snapshotasmesh node
  		sc = point3 scaleFactor scaleFactor scaleFactor
  		verts = for v=1 to meshop.getnummapverts _mesh channel collect (meshop.getmapvert _mesh channel v)*sc
  		faces = for f=1 to meshop.getnummapfaces _mesh channel collect meshop.getmapface _mesh channel f
  			
  		mesh name:(node.name + "_uvmesh") vertices:verts faces:faces	
  	)
  
  	fn BuildUvMesh node channel:1 fixelements:false size:1.0 realscale:true = 
  	(
  		local m1 = snapshotasmesh node
  		local numtverts = meshop.getnummapverts m1 channel
  		local getmapvert = meshop.getmapvert
  		local getmapface = meshop.getmapface
  		local verts = for j = 1 to numtverts collect (getmapvert m1 channel j)*[size,size,0]
  		
  		meshop.setnumverts m1 numtverts
  		meshop.setvert m1 #{1..numtverts} verts
  		
  		for j = 1 to m1.numfaces do
  		(
  			face = getmapface m1 channel j
  			setface m1 j face[1] face[2] face[3]
  		)
  		mesh mesh:m1
  		delete m1
  		gc light:true		
  	)	
  	
  	
  	for nn = 1 to 2 do
  	(
  		delete objects
  
  		b = box()
  		modi = Unwrap_UVW()
  		addmodifier b modi
  		max modify mode
  		select b
  		modpanel.setcurrentobject modi
  		modi.flattenMapNoParams()
  		max create mode
  		clearselection()
  		addmodifier b (tessellate tension:0 iterations:3)
  		addmodifier b (tessellate tension:0 iterations:1)
  		gc()
  		
  		st = timestamp(); sh = heapfree
  		
  		if nn == 1 then uvToMesh b scaleFactor:100.0
  		 else BuildUvMesh b size:100.0
  		
  		format "faces:% time:% memory:%

" b.numfaces (timestamp()-st) (sh-heapfree)
  	)
  	
  )

I’ve tested with 3 and 4 iterations on this line:

 addmodifier b (tessellate tension:0 iterations:3)

3 Iterations
faces:49152 time:94 memory:9569776L
faces:49152 time:118 memory:1654936L

4 Iterations
faces:196608 time:1174 memory:37993360L
faces:196608 time:1225 memory:6422696L


#50

Yes Denis, it does indeed triangulate the output uvw mesh. Try with a single teapot.


#51

ok… ok… yes. my triangulates. :slight_smile: well. do your way


#52

actually… why the uv mesh should not to be triangulated? the edge visibility of source mesh based on:
#1 creation algorithm
#2 flatness of surrounded faces
in general case the uv might not match any of these conditions. so the not-triangulating the mesh is an subjective action as well as the triangulating.


#53

Well, your way looks in fact pretty similar to some approach I posted here a while back, in which I removed the vertex position for optimization purposes.

So, as you can see, I had already evaluated that possibility but decided to not keep using it for the very same reasons I mentioned earlier, triangulation and shifted uvw.

It doesn’t mean it can’t be used, it is just that for this script I consider that the uvw topology is something that needs to be preserved. At least that is what I would expect from a script like this.

Also in the test I forgot to remove the delete and gc() lines from my function, which would make it run around 10-20% faster.

Overall, we are comparing the performance of two functions that leads to different results.


#54

This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.