Update: So I’ve made an odd discovery. Turns out if you put more than one material on an object, they get drawn together. Essentially this means that the script isn’t needed at all. Character Creation is much easier this way as well.
The downside? It increases draw calls with every material added. I wonder though, would Texture2D.PackTextures make the resulting texture layered as well? At that point, I could use that to pack the textures into a texture atlas, merging the materials and reducing it to a single draw call (assuming the clothing materials all matched types, but that’s an easy issue).
Old Post:
So I have a few functions so far, working together to set up a character for use. It’s pretty hefty, because it combines several layers of clothing into one single texture (like World of Warcraft, although my system doesn’t seem to be nearly as smooth).
Right now what I’m doing is simply calling this function on Awake(). I’ve managed to set up about 62 objects this way (with only a few layers) without failure, but beyond that the function can sometimes fail to finish, and makes the textures all black.
Also, about half the time, 512x512 can be too big for the function to process all at once. 256x256 seems to work fine, but at that point I would be sacrificing a lot.
Is there some way I could simply have my script work in the background, and only apply when it’s ready?
Also, can you see anything I could do to improve my script’s overall performance? Here’s the real meat of it:
public static TextureLayer FlattenLayers(List<TextureLayer> layers) {
TextureLayer returnLayer = new TextureLayer();
List<Texture2D> flattenTextures = new List<Texture2D>();
List<Texture2D> flattenNormals = new List<Texture2D>();
List<Color> addedColors = new List<Color>();
foreach(TextureLayer texLayer in layers) {
if(texLayer.texture != null) { flattenTextures.Add(texLayer.texture); }
else { flattenTextures.Add(null); }
if(texLayer.normalTexture != null) { flattenNormals.Add(texLayer.normalTexture); }
else { flattenNormals.Add(null); }
addedColors.Add(texLayer.color);
}
returnLayer.texture = TextureCombineUtility.Flatten(flattenTextures,flattenTextures,addedColors);
returnLayer.normalTexture = TextureCombineUtility.Flatten(flattenNormals,flattenTextures,addedColors);
return returnLayer;
}
public static Texture2D Flatten (List<Texture2D> combines, List<Texture2D> alphaSource, List<Color> colorSource) {
Texture2D newTexture = new Texture2D(0,0,TextureFormat.ARGB32,true);
newTexture.SetPixel(0,0,Color.white);
if(combines[0]) {
newTexture.Resize(combines[0].width,combines[0].height,TextureFormat.ARGB32,true);
}
else {
newTexture.Resize(256,256,TextureFormat.ARGB32,true);
}
int xx = newTexture.width;
int yy = newTexture.height;
//Resize each layer to match the new texture, and draw the layer onto the new texture.
int i = 0;
int l = combines.Count;
while(i < l) {
if(combines[i]) {
Texture2D addTex = new Texture2D(combines[i].width,combines[i].height,TextureFormat.ARGB32,true);
addTex.SetPixels(combines[i].GetPixels(0),0);
addTex.Resize(xx,yy,TextureFormat.ARGB32,true);
Texture2D alphaTex = new Texture2D(0,0,TextureFormat.ARGB32,true);
alphaTex.SetPixel(0,0,Color.white);
if(alphaSource[i]) {
alphaTex.Resize(alphaSource[i].width,alphaSource[i].height,TextureFormat.ARGB32,true);
alphaTex.SetPixels(alphaSource[i].GetPixels(0),0);
}
alphaTex.Resize(xx,yy,TextureFormat.ARGB32,true);
int y = 0;
while(y < yy) {
int x = 0;
while(x < xx) {
Color mainPixel = newTexture.GetPixel(x,y);
Color newPixel = addTex.GetPixel(x,y);
Color alphaPixel = alphaTex.GetPixel(x,y);
Color colorChange = colorSource[i];
mainPixel = Color.Lerp(mainPixel,newPixel*colorChange,alphaPixel.a);
newTexture.SetPixel(x,y,mainPixel);
++x;
}
++y;
}
}
++i;
}
newTexture.Apply();
return newTexture;
}