Notifications
Clear all

[Closed] Break vertex by vertex color

Hi,
I need to export as .fbx a mesh with vertex color by face.
Fbx doesn’t create extra vert to support it, so i need to manually break vertex.

I was thinking of breaking all vertex on mesh.
Then parse the vertex color channel to get each mapvert position,
then select and weld vertices on the mesh, that have the same position on vertex color channel (aka same color)

Here’s a humble start, thanks to Polytools, to get the coordinates of every vertex in the vertex color channel.


fn vc node =	
(
	--vc channel
	channel = 0
	--get tvert pos
	obj = snapshotasmesh node
	numtverts = meshop.getnummapverts obj channel
	getmapvert = meshop.getmapvert
	verts = for j = 1 to numtverts collect (getmapvert obj channel j)
)

vc $

From here i’d need to select a group of vertices that have the same uv0 coordinates (and maybe same geo position) and weld that group.
Then select another group and weld, and so on.

First i’m not sure how to get indexes of vertex sharing the same coordinates, also considering that when welding vertices, vertex indexes get shifted.
Thanks for helping.

11 Replies

Ok, new idea !
This is what i get when i weld vertex color “uvw’s”

So i guess i could rebuild the mesh from the uv channel.
I probably have everything from Jorge and Denis there
http://forums.cgsociety.org/showthread.php?t=1158192
and just have to be smart :s

Hi Clanker,

    It is a little confusing what you are trying to achieve. You say you want to export the "..vertex color by face...", what does it mean?
    
    Also, I am not sure why you need to breack and weld the mesh.
    
    Do you have a sample of the output data you need? For example, do you need an array of vertices colors, and array of vertices grouped by faces?
    
    Perhaps you could elaborate the idea using a default plane() mesh?
    
   Does the following code work for what you need? 
fn GetVertexColorArrayByFace node =
 (
 	local mesh = node.mesh
 	local faces = #()
 
 	for j = 1 to mesh.numfaces do
 	(
 		local fvc = getvcface mesh j
 		local face = for v = 1 to 3 collect (getvertcolor mesh fvc[v]) as point3	-- 255 range
 		--local face = for v = 1 to 3 collect meshop.getmapvert mesh 0 fvc[v]		-- 1.0 range
 		append faces face
 	)
 	return faces
 )
   Thank you!
    Jorge

Haaa thanks for passing by !
Well, I like to break and weld stuff, don’t you know it ?

So, Max allows users to paint vertex color by face or vertex.

Note that here, all vertices are welded.
Since channels are independent, it’s not a big deal.

But fbx format doesnt support it. 1 vertex = 1 color.
See that picture, after export/import as fbx.

If i want a color “by face” at export, i need to break the mesh, to create extra vertex to support the vertex color. So break geometry edges in yellow here :

So that’s why i was thinking to break all vertices, parse them, and weld those with the same color.

Then, i tried to weld “uvs” of the vertex color channel (as all faces are exploded by default), build a mesh from it, and repostioning every vertex to the orignal mesh vertex position. It almost worked but some vertices were misplaced on top of others.

Sorry, I am still confused. It must be these cold days here. Anyway, does the following code work for you?

  PS: If it does work, it is just by pure coincidence.
fn BreakMeshByFacesColors node =
    (
    	mesh = node.mesh
    
    	colors = #()
    	groups = #()
    	
    	for j = 1 to mesh.numfaces do
    	(
    		fvc = getvcface mesh j
    		for i = 1 to 3 do
    		(
    			vc = getvertcolor mesh fvc[i]
    			idx = finditem colors vc
    			
    			if idx == 0 then
    			(
    				append colors vc
    				append groups #{j}
    			)else(
    				append groups[idx] j
    			)
    		)
    			
    	)
    	for j in groups do meshop.detachfaces mesh j delete:true
    )

Nope that’s not it.
There shouldnt be any detachfaces involved.
New picture. Not sure how to explain it better.

Thanks for your time !

Finally, I think I now understand what you need.

Basically, if I am not wrong again, what you want is to break all geometry vertices that have multiple vertex colors, and keep the ones with same vertex color welded.

Ok, first step first, assuming you can’t work with Editable Poly let’s see if this code does the work:

(
  	fn BreakMeshByFacesColors node =
  	(
  		mesh = copy node.mesh
  
  		vertscolors = #()
  		colorsarray = #()
  		vertsbyface = #()
  		flagedverts = #{}
  		
  		for j = 1 to mesh.numfaces do
  		(
  			faceg = getface mesh j
  			facec = getvcface mesh j
  			
  			for i = 1 to 3 do
  			(
  				vcolor = getvertcolor mesh facec[i]
  				
  				if vertscolors[faceg[i]] == undefined then
  				(
  					vertscolors[faceg[i]] = vcolor
  				)else(
  					if vertscolors[faceg[i]] != vcolor do flagedverts[faceg[i]] = true
  				)
  			)
  		)
  
  		setvertselection mesh flagedverts
  		meshop.breakverts mesh flagedverts
  
  		flagedverts = getvertselection mesh
  		sharedfaces = meshop.getfacesusingvert mesh flagedverts
  
  		for j in sharedfaces do
  		(
  			faceg = getface mesh j
  			facec = getvcface mesh j
  			
  			for i = 1 to 3 where flagedverts[faceg[i]] do
  			(
  				vcolor = getvertcolor mesh facec[i]
  				found = finditem colorsarray vcolor
  
  				if found == 0 then
  				(
  					append colorsarray vcolor
  					append vertsbyface #([j,i])
  				)else(
  					append vertsbyface[found] [j,i]
  				)
  			)
  		)
  
  		for j in vertsbyface do
  		(
  			weldverts = #{}
  			for i in j do
  			(
  				face = getface mesh i[1]
  				weldverts[face[i[2]]] = true
  			)
  			meshop.weldvertsbythreshold mesh weldverts 0.0001
  		)
  		
  		node.mesh = mesh
  		
  	)
  	
  	gc()
  	st = timestamp(); sh = heapfree
  	BreakMeshByFacesColors $
  	format "time:% ram:% 
" (timestamp()-st) (sh-heapfree)
  )

Yep, perfect ! And fast.
I started with poly at first, hence i tried your method to build a mesh from uv channel 0, because the vertex color methods are only for mesh.
Anyway, i can convert my models back and forth to poly/mesh, shouldn’t be a problem.
Thank you, you save the day once again.

I am glad it worked, it could be much faster and cleaner, but if it works and does it fast for you then it’s done.

The bigest slow down, is as usual, due to the meshop weldverts operation, but it could be done in a different way to speed it up.

Hey Jorge,
Would you mind to help me some more ?
I’m trying adapt your code to break vertex color in conjunction with vertex alpha too (channel -2).
So if a vertex shared by 2 faces is of the same color, but different vertex alpha, it should be splitted.

I think i got the first part, breaking all geo vert that has different color or alpha.


  fn BreakMeshByFacesColors2 node =
  (
  		  mesh = copy node.mesh
    
  		  vertscolors = #()
  		vertsalphas = #()
  	
  		  colorsarray = #()
  		alphaarray = #()
  	
  		  vertsbyface = #()
  		  flagedverts = #{}
  		  
  		--for each face
  		  for j = 1 to mesh.numfaces do
  		  (
  			  --get 3 geo verts
  			faceg = getface mesh j
  			--get 3 color verts
  			  facec = getvcface mesh j
  			--get 3 alpha verts
  			facea = meshop.getMapFace mesh -2 j
  			  
  			--for each vertex
  			  for i = 1 to 3 do
  			  (
  				--get vertex color
  				  vcolor = getvertcolor mesh facec[i]
  				--get alpha
  				valpha = meshop.getMapVert mesh -2 facea[i]-- range 0-1, getalpha instead ?
  				
  				--if geo vert had a different color/alpha, store it in flagedverts
  				if vertscolors[faceg[i]] == undefined  then
  				  (
  					  vertscolors[faceg[i]] = vcolor
  				  )else(
  					if vertscolors[faceg[i]] != vcolor or vertsalphas[faceg[i]] != valpha do flagedverts[faceg[i]] = true
  				)
  						
  				if vertsalphas[faceg[i]] == undefined then
  				  (
  					vertsalphas[faceg[i]] = valpha
  				  )else(
  					  if vertsalphas[faceg[i]] != valpha do flagedverts[faceg[i]] = true
  				  )											
  			  )
  		  )
    
  		--break flaged verts
  		  setvertselection mesh flagedverts
  		  meshop.breakverts mesh flagedverts
    
  		  flagedverts = getvertselection mesh
  		--faces using flagedverts
  		  sharedfaces = meshop.getfacesusingvert mesh flagedverts
  

Then i struggle big time with logic.
I end up with open edges only where both color and alpha are different. Been trying to move blocks around all afternoon.
Thanks.

Page 1 / 2