Created
May 17, 2018 10:50
-
-
Save zcyemi/1c9b4da7ff68e48106c30d1aa0151cec to your computer and use it in GitHub Desktop.
Unity editor script for merging sprite render sprites into a single large mesh.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
using UnityEditor; | |
public class SpriteMeshMerger | |
{ | |
[MenuItem("MeshGen/BuildMesh")] | |
public static void TestGenMesh() | |
{ | |
var selections = Selection.gameObjects; | |
CombinedMesh(selections); | |
} | |
private static readonly float SORTING_ORDER_SCALING = 0.000001f; | |
private static readonly string MESH_PATH = "Assets/SpriteMeshGen/"; | |
public static void CombinedMesh(GameObject[] objs) | |
{ | |
Dictionary<Transform, SpriteRenderer> sprdic = new Dictionary<Transform, SpriteRenderer>(); | |
Vector3 posaccu = Vector3.zero; | |
string atlasName = null; | |
foreach (var obj in objs) | |
{ | |
var sr = obj.GetComponent<SpriteRenderer>(); | |
if (sr == null) continue; | |
if (sr.sprite == null) continue; | |
atlasName = sr.sprite.texture.name; | |
sprdic.Add(obj.transform, sr); | |
posaccu += obj.transform.position; | |
} | |
if (sprdic.Count == 0) | |
{ | |
Debug.Log("no valid sprite render"); | |
return; | |
} | |
Vector3 meshPos = posaccu / sprdic.Count; | |
meshPos.z = 0; | |
List<Vector3> vert = new List<Vector3>(); | |
List<Vector2> uv = new List<Vector2>(); | |
List<int> indices = new List<int>(); | |
List<Color> color = new List<Color>(); | |
int totalVertCount = 0; | |
foreach (var pair in sprdic) | |
{ | |
var spr = pair.Value.sprite; | |
Vector2 textureTexel = spr.texture.texelSize; | |
var sprcenter = spr.bounds.center; | |
Debug.Log("SpriteBound center:" + FmtVec2(sprcenter)); | |
Debug.Log("SpriteBound size:" + FmtVec2(spr.bounds.size)); | |
var rootpos = pair.Key.position - meshPos + sprcenter; | |
Color srColor = pair.Value.color; | |
Vector3 scale = pair.Key.lossyScale; | |
Quaternion rota = pair.Key.rotation; | |
Vector2 flip = new Vector2((pair.Value.flipX ? -1f : 1f), (pair.Value.flipY ? -1F : 1F)); | |
int sprVertCount = spr.vertices.Length; | |
int sprVertCountTiled = 0; | |
var sr = pair.Value; | |
Vector2 textureSize = new Vector2(spr.texture.width, spr.texture.height); | |
List<Vector3> sprVertices = spr.vertices.Select(v => new Vector3(v.x, v.y, 0)).ToList(); | |
if (sr.drawMode == SpriteDrawMode.Simple) | |
{ | |
Debug.Log("SpriteCenter: " + FmtVec2(sprcenter)); | |
foreach (var v in sprVertices) | |
{ | |
Vector3 sprv = v; | |
//F | |
sprv.x *= flip.x; | |
sprv.y *= flip.y; | |
//S | |
sprv.x *= scale.x; | |
sprv.y *= scale.y; | |
//R | |
sprv = rota * sprv; | |
//T | |
sprv.x -= sprcenter.x; | |
sprv.y -= sprcenter.y; | |
//Depth; | |
sprv.z = pair.Value.sortingOrder * SORTING_ORDER_SCALING; | |
sprv += rootpos; | |
vert.Add(sprv); | |
color.Add(srColor); | |
} | |
var indlen = spr.triangles.Length; | |
for (var i = 0; i < indlen; i++) | |
{ | |
indices.Add(totalVertCount + spr.triangles[i]); | |
} | |
uv.AddRange(spr.uv); | |
totalVertCount += sprVertices.Count; | |
} | |
else if (sr.drawMode == SpriteDrawMode.Tiled) | |
{ | |
Vector2 tileSize = spr.rect.size / spr.pixelsPerUnit; | |
Debug.Log("unitsize: " + tileSize.x + " " + tileSize.y); | |
Vector2 itemCount = new Vector2(sr.size.x / tileSize.x, sr.size.y / tileSize.y); | |
Vector2 rootPosOffset = itemCount - Vector2.one; | |
rootPosOffset.x *= -.5f * tileSize.x; | |
rootPosOffset.y *= -.5f * tileSize.y; | |
int tileCountX = Mathf.CeilToInt(itemCount.x); | |
int tileCountY = Mathf.CeilToInt(itemCount.y); | |
Debug.Log(tileCountX + " " + tileCountY); | |
Debug.Log(itemCount.x + " " + itemCount.y); | |
for (int tiley = 0; tiley < tileCountY; tiley++) | |
{ | |
for (int tilex = 0; tilex < tileCountX; tilex++) | |
{ | |
bool clipx = false; | |
bool clipy = false; | |
Vector2 clipMax = Vector2.zero; | |
if (tilex == tileCountX - 1) | |
{ | |
float xoff = itemCount.x - tilex; | |
clipMax.x = (xoff - 0.5f) * tileSize.x; | |
clipx = true; | |
} | |
if (tiley == tileCountY - 1) | |
{ | |
float yoff = itemCount.y - tiley; | |
clipMax.y = (yoff - 0.5f) * tileSize.y; | |
clipy = true; | |
} | |
int index = 0; | |
foreach (var v in sprVertices) | |
{ | |
Vector3 sprv = v; | |
Vector2 uvcoord = spr.uv[index]; | |
if (clipx) | |
{ | |
if (sprv.x > clipMax.x) | |
{ | |
uvcoord.x -= (sprv.x - clipMax.x) * spr.pixelsPerUnit / textureSize.x; | |
sprv.x = clipMax.x; | |
} | |
} | |
if (clipy) | |
{ | |
if (sprv.y > clipMax.y) | |
{ | |
uvcoord.y -= (sprv.y - clipMax.y) * spr.pixelsPerUnit / textureSize.y; | |
sprv.y = clipMax.y; | |
} | |
} | |
uv.Add(uvcoord); | |
color.Add(srColor); | |
//TileOffset | |
sprv.x += rootPosOffset.x + tilex * tileSize.x; | |
sprv.y += rootPosOffset.y + tiley * tileSize.y; | |
//F | |
sprv.x *= flip.x; | |
sprv.y *= flip.y; | |
//S | |
sprv.x *= scale.x; | |
sprv.y *= scale.y; | |
//R | |
sprv = rota * sprv; | |
//T | |
//Depth; | |
sprv.z = pair.Value.sortingOrder * SORTING_ORDER_SCALING; | |
sprv += rootpos; | |
vert.Add(sprv); | |
index++; | |
} | |
var indlen = spr.triangles.Length; | |
for (var i = 0; i < indlen; i++) | |
{ | |
indices.Add(totalVertCount + spr.triangles[i]); | |
} | |
totalVertCount += sprVertices.Count; | |
} | |
} | |
} | |
} | |
Mesh mesh = new Mesh(); | |
mesh.SetVertices(vert); | |
mesh.SetUVs(0, uv); | |
mesh.SetIndices(indices.ToArray(), MeshTopology.Triangles, 0); | |
mesh.SetColors(color); | |
mesh.UploadMeshData(false); | |
string gname = "SprMesh_" + atlasName + "_mesh"; | |
GameObject g = GameObject.Find(gname) ?? new GameObject("SprMesh_" + atlasName + "_mesh"); | |
if (g.GetComponent<MeshRenderer>() == null) g.AddComponent<MeshRenderer>(); | |
if (g.GetComponent<MeshFilter>() == null) g.AddComponent<MeshFilter>(); | |
g.GetComponent<MeshFilter>().mesh = mesh; | |
g.transform.position = meshPos; | |
AssetDatabase.CreateAsset(mesh, MESH_PATH + gname + System.DateTime.UtcNow.ToFileTime() + ".asset"); | |
PrefabUtility.CreatePrefab(MESH_PATH + gname + System.DateTime.UtcNow.ToFileTime() + ".prefab", g, ReplacePrefabOptions.Default); | |
} | |
public static string FmtVec3(Vector3 v) | |
{ | |
return string.Format("<{0},{1},{2}>", v.x, v.y, v.z); | |
} | |
public static string FmtVec2(Vector2 v) | |
{ | |
return string.Format("<{0},{1}>", v.x, v.y); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment