[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.
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.