- Home /
Texture-Atlas Modifying Mesh UVs
I am trying to combine multiple textures into a texture atlas using Texture2D.PackTextures() which works fine. I create a new material for all the materials used on my mesh and sub-meshes. I end up with a new Packed Texture with 4 images.
This new material using the texture atlas is then applied to all my mesh and submeshes.
I then modify the UVs of my mesh and submeshes to point to the new image within the texture atlas. But what I seem to get is the complete texture atlas being used as the single texture, rather than the image within the atlas.
This is what I am expecting (apologies for the dark colours, there's no lights in my test scene!):
And this is what I get:
I've checked the UVs and they look to be getting updated correctly.
Any ideas as to what I'm missing?
This is my code snippet, its nothing fancy.
Material atlasMaterial = new Material(Shader.Find("Diffuse Fast")); Component[] filters = GetComponentsInChildren(typeof(MeshFilter));
Texture2D[] textures = new Texture2D[filters.Length];
for (int i=0 ; i<filters.Length ; i++) { textures[i] = (Texture2D)filters[i].gameObject.renderer.material.mainTexture; }
textureAtlas=new Texture2D(maxSquareTextureSize,maxSquareTextureSize); Rect[] uvs = textureAtlas.PackTextures(textures,0,maxSquareTextureSize);
atlasMaterial.mainTexture = textureAtlas;
Vector2[] oldUV,newUV; for (int i=0 ; i<filters.Length ; i++) {
filters[i].gameObject.renderer.material=atlasMaterial; oldUV = (Vector2[])(((MeshFilter)filters[i]).mesh.uv); newUV = new Vector2[oldUV.Length]; for (int j=0 ; j<oldUV.Length ; j++) { newUV[j]=new Vector2((oldUV[j].x*uvs[i].width)+uvs[i].x, (oldUV[j].y*uvs[i].height)+uvs[i].y); }
((MeshFilter)filters[i]).mesh.uv=newUV;
}
I am guessing here but worked many years with unwrapping UVs. It appears that the UV's are still going from 0-1 for each submesh from the dark pics above. If the width is 0-1 I don't see where you have percentiled or scaled and offset the sub UV sets. I see them iterated over and multiplied but not percentiled according to the new rect. I may be barking up a wrong tree here as the script looks fine but that is where I would head next if I was trying to crack this nut. Am doing this scheduled next week for a bunch of stuff.
hmmm... that should be accounted for from the uvs[] array, and I'm sure I saw the UVs co$$anonymous$$g out as 0,0.5,1,1.5 etc. But I will certainly look into that and make sure!
Thanks.
Answer by Max Kaufmann · Dec 13, 2010 at 03:12 AM
It might be this line:
((MeshFilter)filters[i]).mesh.uv=newUV;
In general, you should use .sharedMesh wherever you're using .mesh right now; the latter acts like a value-type and returns a copy, which is probably not what you want.
Answer by d3coy · Jan 02, 2011 at 06:45 AM
My bet is that the textures array being packed wasn't full of single occurrence items (like in a Set). This code has the fundamental assumption that there is a 1:1 correspondence between texture, rectangle, and meshfilter, when this may not be the case at all.
First a verified Set of Texture2D should be used as the input textures. Then when choosing a rectangle for any particular Mesh, make sure to get the proper index into the Rectangles array using the Mesh's texture, with Array.IndexOf.
This also means that the various game objects should not be set to the new material until the UV's have been adjusted, since the mainTexture is needed to do the rectangle lookup.
I realize this is an old question, but figured someone might be wondering the same thing.
Your answer
Follow this Question
Related Questions
image stretched when packing textures in large size 1 Answer
Texture2D.PackTextures Only Packing First Texture 0 Answers
Coding my own auto-slicer, getting "islands" of pixels at runtime? 1 Answer
Best way to atlas texture2Ds used on quads? 0 Answers
Texture2D.PackTextures - attempt to determine if texture was scaled 0 Answers