I’ve working on a character customization script, where you can change the vertex colors of an object. I’ve tried a number of ways, but every time it leaves artifacts, except for one way, which only allows you to replace every instance of a specific color in a mesh. This doesn’t allow me to isolate specific parts of a mesh, as after updating the colors in the mesh, each those parts of the mesh are now grouped with other parts that match the same color.
The following is a couple of the ways I’ve tried, with the TryAgain method working, but failing me in the ways described above.
To start, I’ve created a cube, subdivided, where each of the six sides of the cube is a different color consisting of multiple actual faces, and then applied a vertex color shader.
When I replace the color, the edges of the cube near the next side of the cube are the spots where the artifacts from the previous color remain, leaving a splotchy mess. It was my understanding that to preserve hard edges, Unity splits the faces of the mesh, and so instead of a cube having 8 vertices, when imported from Blender it reads as 24, which lead me to believe that it should work, but after the result I had, I even split the faces manually and imported the cube and was left with the same result.
After numerous attempts, I even looped through every vertex and separated the indices into different lists based on color, and still, artifacts. This is the failed method that lies below.
The goal is to figure out what I’m doing wrong in the ChangeColor method so that it will completely fill the face as it does in the TryAgain method, while still allowing me to divide and change the colors of the mesh by vertex, rather than just looping through and replacing all instances of a specific color.
A assigns the mesh, B uses the method that leaves artifacts, Space will restore the original colors of the mesh, and C uses the method that doesn’t leave artifacts, however doesn’t allow me to isolate the color to change by group of vertices/face. Keys 1-6 will change which face is adjusted. Everything is public for simplicity sake the only thing you need to do is attach the script and drag a GameObject with a mesh renderer into the activeMeshObject in the inspector. As previously stated I used a a sub divided cube with each side consisting of subdivided faces of the same color, but anything with a vertex color shader and faces that are flood filled with a single color should demonstrate the problem, provided there’s only six different colors.
There’s definitely a chance I’m just making some stupid mistake, any help is appreciated.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
public class ColorChangeDebug : MonoBehaviour
{
public GameObject activeMeshObject;
public Mesh activeMesh;
public Color fillColor;
public Color[] originalColors;
public bool colorsChanged;
public List<int> distinctVertColorIndexList1;
public List<int> distinctVertColorIndexList2;
public List<int> distinctVertColorIndexList3;
public List<int> distinctVertColorIndexList4;
public List<int> distinctVertColorIndexList5;
public List<int> distinctVertColorIndexList6;
public List<int> vertIndexList;
public int numberOfIndexLists;
public Color colorToReplace;
public List<Color> distinctMeshColors;
public List<Color> meshColors;
public List<Vector3> meshVerts;
public int currentIndexList;
public int cubeSide;
void Start()
{
fillColor = Color.black;
}
void Update()
{
if (Input.GetKeyUp(KeyCode.A)) { AssignMesh(); }
if (Input.GetKeyUp(KeyCode.Space) && colorsChanged == true) //Restores original Colors
{
activeMesh.colors = originalColors;
colorsChanged = false;
}
else if (Input.GetKeyUp(KeyCode.B) && colorsChanged == false) //Leaves artifacts
{
ChangeColor();
colorsChanged = true;
}
else if (Input.GetKeyUp(KeyCode.C) && colorsChanged == false) //Gets proper hard edges and leaves no artifacts, but won't allow me to target specific vertices of a mesh.
{
TryAgain();
colorsChanged = true;
}
if (Input.GetKeyUp(KeyCode.Keypad1)) { currentIndexList = 1; UpdateIndexList(); } //Changes side of cube that will change color.
else if (Input.GetKeyUp(KeyCode.Keypad2)) { currentIndexList = 2; UpdateIndexList(); }
else if (Input.GetKeyUp(KeyCode.Keypad3)) { currentIndexList = 3; UpdateIndexList(); }
else if (Input.GetKeyUp(KeyCode.Keypad4)) { currentIndexList = 4; UpdateIndexList(); }
else if (Input.GetKeyUp(KeyCode.Keypad5)) { currentIndexList = 5; UpdateIndexList(); }
else if (Input.GetKeyUp(KeyCode.Keypad6)) { currentIndexList = 6; UpdateIndexList(); }
}
void AssignMesh()
{
activeMesh = activeMeshObject.GetComponent<MeshFilter>().sharedMesh;
Mesh clonedMesh = (Mesh)Instantiate(activeMesh);
activeMeshObject.GetComponent<MeshFilter>().sharedMesh = clonedMesh;
activeMesh = clonedMesh;
originalColors = activeMesh.colors;
GetMeshColors();
GetVertListsByColor();
}
void ChangeColor()
{
activeMesh.GetColors(meshColors);
foreach (int index in vertIndexList)
{
meshColors[index] = fillColor;
}
activeMesh.SetColors(meshColors);
}
void TryAgain()
{
Color[] temporaryColorArray = activeMesh.colors;
colorToReplace = distinctMeshColors[cubeSide];
foreach (Color col in temporaryColorArray)
{
if (col == colorToReplace)
{
int index = System.Array.IndexOf(temporaryColorArray, col);
Color temporaryCol = fillColor;
temporaryColorArray[index] = temporaryCol;
}
}
activeMesh.colors = temporaryColorArray;
}
void UpdateIndexList()
{
switch (currentIndexList)
{
case 1:
vertIndexList = distinctVertColorIndexList1;
cubeSide = 0;
break;
case 2:
vertIndexList = distinctVertColorIndexList2;
cubeSide = 1;
break;
case 3:
vertIndexList = distinctVertColorIndexList3;
cubeSide = 2;
break;
case 4:
vertIndexList = distinctVertColorIndexList4;
cubeSide = 3;
break;
case 5:
vertIndexList = distinctVertColorIndexList5;
cubeSide = 4;
break;
case 6:
vertIndexList = distinctVertColorIndexList6;
cubeSide = 5;
break;
}
}
void GetVertListsByColor()
{
currentIndexList = 1;
UpdateIndexList();
foreach (Color distinctCol in distinctMeshColors)
{
foreach (Vector3 vert in meshVerts)
{
int vertIndex = meshVerts.IndexOf(vert);
if (meshColors[vertIndex] == distinctCol)
{
vertIndexList.Add(vertIndex);
}
}
currentIndexList++;
UpdateIndexList();
}
}
void GetMeshColors()
{
if (activeMesh != null)
{
activeMesh.GetColors(meshColors);
activeMesh.GetVertices(meshVerts);
distinctMeshColors = meshColors.Distinct().ToList();
}
}
}
