398 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			398 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.IO;
 | 
						|
using UnityEngine;
 | 
						|
 | 
						|
// A simple mesh saving/loading functionality.
 | 
						|
// This is an utility script, you don't need to add it to any objects.
 | 
						|
// See SaveMeshForWeb and LoadMeshFromWeb for example of use.
 | 
						|
//
 | 
						|
// Uses a custom binary format:
 | 
						|
//
 | 
						|
//    2 bytes vertex count
 | 
						|
//    2 bytes triangle count
 | 
						|
//    1 bytes vertex format (bits: 0=vertices, 1=normals, 2=tangents, 3=uvs)
 | 
						|
//
 | 
						|
//    After that come vertex component arrays, each optional except for positions.
 | 
						|
//    Which ones are present depends on vertex format:
 | 
						|
//        Positions
 | 
						|
//            Bounding box is before the array (xmin,xmax,ymin,ymax,zmin,zmax)
 | 
						|
//            Then each vertex component is 2 byte unsigned short, interpolated between the bound axis
 | 
						|
//        Normals
 | 
						|
//            One byte per component
 | 
						|
//        Tangents
 | 
						|
//            One byte per component
 | 
						|
//        UVs (8 bytes/vertex - 2 floats)
 | 
						|
//            Bounding box is before the array (xmin,xmax,ymin,ymax)
 | 
						|
//            Then each UV component is 2 byte unsigned short, interpolated between the bound axis
 | 
						|
//
 | 
						|
//    Finally the triangle indices array: 6 bytes per triangle (3 unsigned short indices)
 | 
						|
 | 
						|
[Serializable]
 | 
						|
public class MeshSerializer : MonoBehaviour
 | 
						|
{
 | 
						|
    // Reads mesh from an array of bytes. Can return null
 | 
						|
    // if the bytes seem invalid.
 | 
						|
	public static Mesh ReadMesh(byte[] bytes)
 | 
						|
	{
 | 
						|
		if (bytes == null || bytes.Length < 5)
 | 
						|
		{
 | 
						|
			print("Invalid mesh file!");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
 | 
						|
		BinaryReader buf = new BinaryReader(new MemoryStream(bytes));
 | 
						|
		
 | 
						|
        // read header
 | 
						|
        UInt16 vertCount = buf.ReadUInt16();
 | 
						|
		UInt16 triCount = buf.ReadUInt16();
 | 
						|
		byte format = buf.ReadByte();
 | 
						|
 | 
						|
        // sanity check
 | 
						|
		if ((int)vertCount < 0 || (int)vertCount > 64000)
 | 
						|
		{
 | 
						|
			print("Invalid vertex count in the mesh data!");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
		if ((int)triCount < 0 || (int)triCount > 64000)
 | 
						|
		{
 | 
						|
			print("Invalid triangle count in the mesh data!");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
		if ((int)format < 1 || ((int)format & 1) == 0 || (int)format > 15)
 | 
						|
		{
 | 
						|
			print("Invalid vertex format in the mesh data!");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
 | 
						|
		Mesh mesh = new Mesh();
 | 
						|
		int i;
 | 
						|
 | 
						|
        // positions
 | 
						|
		Vector3[] verts = new Vector3[(int)vertCount];
 | 
						|
		ReadVector3Array16bit(verts, buf);
 | 
						|
		mesh.vertices = verts;
 | 
						|
 | 
						|
		if (((int)format & 2) != 0) // have normals
 | 
						|
		{
 | 
						|
			Vector3[] normals = new Vector3[(int)vertCount];
 | 
						|
			ReadVector3ArrayBytes(normals, buf);
 | 
						|
			mesh.normals = normals;
 | 
						|
		}
 | 
						|
 | 
						|
		if (((int)format & 4) != 0) // have tangents
 | 
						|
		{
 | 
						|
			Vector4[] tangents = new Vector4[(int)vertCount];
 | 
						|
			ReadVector4ArrayBytes(tangents, buf);
 | 
						|
			mesh.tangents = tangents;
 | 
						|
		}
 | 
						|
 | 
						|
		if (((int)format & 8) != 0) // have UVs
 | 
						|
		{
 | 
						|
			Vector2[] uvs = new Vector2[(int)vertCount];
 | 
						|
			ReadVector2Array16bit(uvs, buf);
 | 
						|
			mesh.uv = uvs;
 | 
						|
		}
 | 
						|
        // triangle indices
 | 
						|
		int[] tris = new int[(int)triCount * 3];
 | 
						|
		for (i = 0; i < (int)triCount; i++)
 | 
						|
		{
 | 
						|
            tris[i * 3 + 0] = buf.ReadUInt16();
 | 
						|
            tris[i * 3 + 1] = buf.ReadUInt16();
 | 
						|
            tris[i * 3 + 2] = buf.ReadUInt16();
 | 
						|
		}
 | 
						|
		mesh.triangles = tris;
 | 
						|
 | 
						|
		buf.Close();
 | 
						|
 | 
						|
		return mesh;
 | 
						|
	}
 | 
						|
 | 
						|
	public static void ReadVector3Array16bit(Vector3[] arr, BinaryReader buf)
 | 
						|
	{
 | 
						|
		int n = arr.Length;
 | 
						|
        if (n == 0) return;
 | 
						|
 | 
						|
        // Read bounding box
 | 
						|
        Vector3 bmin;
 | 
						|
        Vector3 bmax;
 | 
						|
        bmin.x = buf.ReadSingle();
 | 
						|
        bmax.x = buf.ReadSingle();
 | 
						|
        bmin.y = buf.ReadSingle();
 | 
						|
        bmax.y = buf.ReadSingle();
 | 
						|
        bmin.z = buf.ReadSingle();
 | 
						|
        bmax.z = buf.ReadSingle();
 | 
						|
 | 
						|
        // Decode vectors as 16 bit integer components between the bounds
 | 
						|
        for (int i = 0; i < n; ++i)
 | 
						|
        {
 | 
						|
            UInt16 ix = buf.ReadUInt16();
 | 
						|
            UInt16 iy = buf.ReadUInt16();
 | 
						|
            UInt16 iz = buf.ReadUInt16();
 | 
						|
            float xx = ix / 65535.0f * (bmax.x - bmin.x) + bmin.x;
 | 
						|
            float yy = iy / 65535.0f * (bmax.y - bmin.y) + bmin.y;
 | 
						|
            float zz = iz / 65535.0f * (bmax.z - bmin.z) + bmin.z;
 | 
						|
            arr[i] = new Vector3(xx, yy, zz);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
	public static void WriteVector3Array16bit(Vector3[] arr, BinaryWriter buf)
 | 
						|
	{
 | 
						|
        if (arr.Length == 0) return;
 | 
						|
 | 
						|
        // Calculate bounding box of the array
 | 
						|
        Bounds bounds = new Bounds(arr[0], new Vector3(0.001f, 0.001f, 0.001f));
 | 
						|
        foreach (Vector3 v in arr)
 | 
						|
        {
 | 
						|
            bounds.Encapsulate(v);
 | 
						|
        }
 | 
						|
 | 
						|
        // Write bounds to stream
 | 
						|
        Vector3 bmin = bounds.min;
 | 
						|
        Vector3 bmax = bounds.max;
 | 
						|
        buf.Write(bmin.x);
 | 
						|
        buf.Write(bmax.x);
 | 
						|
        buf.Write(bmin.y);
 | 
						|
        buf.Write(bmax.y);
 | 
						|
        buf.Write(bmin.z);
 | 
						|
        buf.Write(bmax.z);
 | 
						|
 | 
						|
        // Encode vectors as 16 bit integer components between the bounds
 | 
						|
        foreach (Vector3 v in arr)
 | 
						|
        {
 | 
						|
            int xx = (int)Mathf.Clamp(
 | 
						|
                (v.x - bmin.x) / (bmax.x - bmin.x) * 65535.0f,
 | 
						|
                0.0f,
 | 
						|
                65535.0f);
 | 
						|
            int yy = (int)Mathf.Clamp(
 | 
						|
                (v.y - bmin.y) / (bmax.y - bmin.y) * 65535.0f,
 | 
						|
                0.0f,
 | 
						|
                65535.0f);
 | 
						|
            int zz = (int)Mathf.Clamp(
 | 
						|
                (v.z - bmin.z) / (bmax.z - bmin.z) * 65535.0f,
 | 
						|
                0.0f,
 | 
						|
                65535.0f);
 | 
						|
            UInt16 ix = (UInt16)xx;
 | 
						|
            UInt16 iy = (UInt16)yy;
 | 
						|
            UInt16 iz = (UInt16)zz;
 | 
						|
            buf.Write(ix);
 | 
						|
            buf.Write(iy);
 | 
						|
            buf.Write(iz);
 | 
						|
        }
 | 
						|
	}
 | 
						|
 | 
						|
	public static void ReadVector2Array16bit(Vector2[] arr, BinaryReader buf)
 | 
						|
	{
 | 
						|
        int n = arr.Length;
 | 
						|
        if (n == 0) return;
 | 
						|
 | 
						|
        // Read bounding box
 | 
						|
        Vector2 bmin;
 | 
						|
        Vector2 bmax;
 | 
						|
        bmin.x = buf.ReadSingle();
 | 
						|
        bmax.x = buf.ReadSingle();
 | 
						|
        bmin.y = buf.ReadSingle();
 | 
						|
        bmax.y = buf.ReadSingle();
 | 
						|
 | 
						|
        // Decode vectors as 16 bit integer components between the bounds
 | 
						|
        for (int i = 0; i < n; ++i)
 | 
						|
        {
 | 
						|
            UInt16 ix = buf.ReadUInt16();
 | 
						|
            UInt16 iy = buf.ReadUInt16();
 | 
						|
            float xx = ix / 65535.0f * (bmax.x - bmin.x) + bmin.x;
 | 
						|
            float yy = iy / 65535.0f * (bmax.y - bmin.y) + bmin.y;
 | 
						|
            arr[i] = new Vector2(xx, yy);
 | 
						|
        }
 | 
						|
	}
 | 
						|
 | 
						|
	public static void WriteVector2Array16bit(Vector2[] arr, BinaryWriter buf)
 | 
						|
	{
 | 
						|
        if (arr.Length == 0) return;
 | 
						|
 | 
						|
        // Calculate bounding box of the array
 | 
						|
        Bounds bounds = new Bounds(arr[0], new Vector2(0.001f, 0.001f));
 | 
						|
        foreach (Vector2 v in arr)
 | 
						|
        {
 | 
						|
            bounds.Encapsulate(v);
 | 
						|
        }
 | 
						|
 | 
						|
        // Write bounds to stream
 | 
						|
        Vector2 bmin = bounds.min;
 | 
						|
        Vector2 bmax = bounds.max;
 | 
						|
        buf.Write(bmin.x);
 | 
						|
        buf.Write(bmax.x);
 | 
						|
        buf.Write(bmin.y);
 | 
						|
        buf.Write(bmax.y);
 | 
						|
 | 
						|
        // Encode vectors as 16 bit integer components between the bounds
 | 
						|
        foreach (Vector3 v in arr)
 | 
						|
        {
 | 
						|
            int xx = (int)Mathf.Clamp(
 | 
						|
                (v.x - bmin.x) / (bmax.x - bmin.x) * 65535.0f,
 | 
						|
                0.0f,
 | 
						|
                65535.0f);
 | 
						|
            int yy = (int)Mathf.Clamp(
 | 
						|
                (v.y - bmin.y) / (bmax.y - bmin.y) * 65535.0f,
 | 
						|
                0.0f,
 | 
						|
                65535.0f);
 | 
						|
            UInt16 ix = (UInt16)xx;
 | 
						|
            UInt16 iy = (UInt16)yy;
 | 
						|
            buf.Write(ix);
 | 
						|
            buf.Write(iy);
 | 
						|
        }
 | 
						|
	}
 | 
						|
 | 
						|
	public static void ReadVector3ArrayBytes(Vector3[] arr, BinaryReader buf)
 | 
						|
	{
 | 
						|
        //Decode vectors as 8 bit integer components in -1.0 .. 1.0 range
 | 
						|
		int n = arr.Length;
 | 
						|
		for (int i = 0; i < n; ++i)
 | 
						|
		{
 | 
						|
			byte ix = buf.ReadByte();
 | 
						|
			byte iy = buf.ReadByte();
 | 
						|
			byte iz = buf.ReadByte();
 | 
						|
			float xx = ((float)(int)ix - 128f) / 127f;
 | 
						|
			float yy = ((float)(int)iy - 128f) / 127f;
 | 
						|
			float zz = ((float)(int)iz - 128f) / 127f;
 | 
						|
			arr[i] = new Vector3(xx, yy, zz);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public static void WriteVector3ArrayBytes(Vector3[] arr, BinaryWriter buf)
 | 
						|
	{
 | 
						|
        // Encode vectors as 8 bit integer components in -1.0 .. 1.0 range
 | 
						|
		foreach(Vector3 v in arr)
 | 
						|
        {
 | 
						|
			byte ix = (byte)Mathf.Clamp(v.x * 127f + 128f, 0f, 255f);
 | 
						|
			byte iy = (byte)Mathf.Clamp(v.y * 127f + 128f, 0f, 255f);
 | 
						|
			byte iz = (byte)Mathf.Clamp(v.z * 127f + 128f, 0f, 255f);
 | 
						|
			buf.Write(ix);
 | 
						|
			buf.Write(iy);
 | 
						|
			buf.Write(iz);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	public static void ReadVector4ArrayBytes(Vector4[] arr, BinaryReader buf)
 | 
						|
	{
 | 
						|
        //Decode vectors as 8 bit integer components in -1.0 .. 1.0 range
 | 
						|
        int n = arr.Length;
 | 
						|
        for (int i = 0; i < n; ++i)
 | 
						|
        {
 | 
						|
            byte ix = buf.ReadByte();
 | 
						|
            byte iy = buf.ReadByte();
 | 
						|
            byte iz = buf.ReadByte();
 | 
						|
            byte iw = buf.ReadByte();
 | 
						|
            float xx = ((float)(int)ix - 128f) / 127f;
 | 
						|
            float yy = ((float)(int)iy - 128f) / 127f;
 | 
						|
            float zz = ((float)(int)iz - 128f) / 127f;
 | 
						|
            float ww = ((float)(int)iz - 128f) / 127f;
 | 
						|
            arr[i] = new Vector4(xx, yy, zz, ww);
 | 
						|
        }
 | 
						|
	}
 | 
						|
 | 
						|
	public static void WriteVector4ArrayBytes(Vector4[] arr, BinaryWriter buf)
 | 
						|
	{
 | 
						|
        // Encode vectors as 8 bit integer components in -1.0 .. 1.0 range
 | 
						|
        foreach (Vector4 v in arr)
 | 
						|
        {
 | 
						|
            byte ix = (byte)Mathf.Clamp(v.x * 127f + 128f, 0f, 255f);
 | 
						|
            byte iy = (byte)Mathf.Clamp(v.y * 127f + 128f, 0f, 255f);
 | 
						|
            byte iz = (byte)Mathf.Clamp(v.z * 127f + 128f, 0f, 255f);
 | 
						|
            byte iw = (byte)Mathf.Clamp(v.z * 127f + 128f, 0f, 255f);
 | 
						|
            buf.Write(ix);
 | 
						|
            buf.Write(iy);
 | 
						|
            buf.Write(iz);
 | 
						|
            buf.Write(iw);
 | 
						|
        }
 | 
						|
	}
 | 
						|
 | 
						|
    // Writes mesh to an array of bytes.
 | 
						|
	public static byte[] WriteMesh(Mesh mesh, bool saveTangents)
 | 
						|
	{
 | 
						|
		if (!mesh)
 | 
						|
		{
 | 
						|
			print("No mesh given!");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
 | 
						|
		Vector3[] verts = mesh.vertices;
 | 
						|
		Vector3[] normals = mesh.normals;
 | 
						|
		Vector4[] tangents = mesh.tangents;
 | 
						|
		Vector2[] uvs = mesh.uv;
 | 
						|
		int[] tris = mesh.triangles;
 | 
						|
 | 
						|
        // figure out vertex format
 | 
						|
		byte format = (byte)1;
 | 
						|
		if (normals.Length > 0)
 | 
						|
		{
 | 
						|
            format |= 2;
 | 
						|
		}
 | 
						|
		if (saveTangents && tangents.Length > 0)
 | 
						|
		{
 | 
						|
            format |= 4;
 | 
						|
		}
 | 
						|
		if (uvs.Length > 0)
 | 
						|
		{
 | 
						|
            format |= 8;
 | 
						|
		}
 | 
						|
 | 
						|
		MemoryStream stream = new MemoryStream();
 | 
						|
		BinaryWriter buf = new BinaryWriter(stream);
 | 
						|
 | 
						|
        // write header
 | 
						|
		UInt16 vertCount = (UInt16)verts.Length;
 | 
						|
		UInt16 triCount = (UInt16)(tris.Length / 3);
 | 
						|
		buf.Write(vertCount);
 | 
						|
		buf.Write(triCount);
 | 
						|
		buf.Write(format);
 | 
						|
        // vertex components
 | 
						|
		WriteVector3Array16bit(verts, buf);
 | 
						|
		WriteVector3ArrayBytes(normals, buf);
 | 
						|
		if (saveTangents)
 | 
						|
		{
 | 
						|
			WriteVector4ArrayBytes(tangents, buf);
 | 
						|
		}
 | 
						|
		WriteVector2Array16bit(uvs, buf);
 | 
						|
        // triangle indices
 | 
						|
        foreach (int idx in tris)
 | 
						|
        {
 | 
						|
            UInt16 idx16 = (UInt16)idx;
 | 
						|
            buf.Write(idx16);
 | 
						|
        }
 | 
						|
		buf.Close();
 | 
						|
 | 
						|
		return stream.ToArray();
 | 
						|
	}
 | 
						|
 | 
						|
    // Writes mesh to a local file, for loading with WWW interface later.
 | 
						|
	public static void WriteMeshToFileForWeb(Mesh mesh, string name, bool saveTangents)
 | 
						|
	{
 | 
						|
		// Write mesh to regular bytes
 | 
						|
        byte[] bytes = WriteMesh(mesh, saveTangents);
 | 
						|
 | 
						|
        // Write to file
 | 
						|
        FileStream fs = new FileStream(name, FileMode.Create);
 | 
						|
        fs.Write(bytes, 0, bytes.Length);
 | 
						|
        fs.Close();
 | 
						|
	}
 | 
						|
 | 
						|
    // Reads mesh from the given WWW (that is finished downloading already)
 | 
						|
	public static Mesh ReadMeshFromWWW(WWW download)
 | 
						|
	{
 | 
						|
		if (download.error != null)
 | 
						|
		{
 | 
						|
			print("Error downloading mesh: " + download.error);
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!download.isDone)
 | 
						|
		{
 | 
						|
			print("Download must be finished already");
 | 
						|
			return null;
 | 
						|
		}
 | 
						|
 | 
						|
		byte[] bytes = download.bytes;
 | 
						|
 | 
						|
		return ReadMesh(bytes);
 | 
						|
	}
 | 
						|
}
 |