void SerializeMesh(GameObject go, LevelObject lo, bool rejectStatic = true) { MeshFilter mf = go.GetComponent <MeshFilter>(); MeshRenderer mr = go.GetComponent <MeshRenderer>(); bool isBatchStatic = GameObjectUtility.AreStaticEditorFlagsSet(go, StaticEditorFlags.BatchingStatic); bool isLightmapStatic = GameObjectUtility.AreStaticEditorFlagsSet(go, StaticEditorFlags.LightmapStatic); bool shouldBailDueToRejectingStatics = rejectStatic && isBatchStatic; if (mf == null || mf.sharedMesh == null || shouldBailDueToRejectingStatics) { lo.mesh = new LevelMesh(); return; } var m = mf.sharedMesh; var lm = new LevelMesh(); var mNormals = m.normals; var mUV1 = m.uv; var mUV2 = m.uv2; var mTangent = m.tangents; bool hasNormal = mNormals != null && mNormals.Length > 0; bool hasUV1 = mUV1 != null && mUV1.Length > 0; bool hasUV2 = mUV2 != null && mUV2.Length > 0; bool hasTangent = mTangent != null && mTangent.Length > 0; if (hasNormal) { lm.Flags |= LevelMesh.MeshFlags.Normal; } if (hasUV1) { lm.Flags |= LevelMesh.MeshFlags.UV1; } if (hasUV2) { lm.Flags |= LevelMesh.MeshFlags.UV2; } if (hasTangent) { lm.Flags |= LevelMesh.MeshFlags.Tangent; } Profiler.BeginSample("Write Verts"); // TODO: We should reuse the stuff above. // Vertex order is: pos, norm, uv0, [uv1] var uv1 = new List <Vector2>(); var uv2 = new List <Vector2>(); var tangent = new List <Vector4>(); if (hasUV1) { m.GetUVs(0, uv1); } if (hasUV2) { m.GetUVs(1, uv2); } if (hasTangent) { m.GetTangents(tangent); } Profiler.BeginSample("Copy Verts"); var vertByteSize = 3 * 4 + // Position (hasNormal ? 3 * 4 : 0) + // Normal (hasUV1 ? 2 * 4 : 0) + // UV1 (hasUV2 ? 2 * 4 : 0) + // UV2 (hasTangent ? 4 * 4 : 0) // Tangent ; var bytes = new byte[vertByteSize * m.vertexCount]; var stagingFloats = new float[m.vertexCount * 4]; Debug.Assert(m.vertexCount == m.vertices.Length); // Copy vertex data as contiguous runs by field. var offset = 0; offset = MemoryMapUtility.MapVector3ToBytes(m.vertexCount, bytes, 0, stagingFloats, m.vertices); if (hasNormal) { Debug.AssertFormat(m.vertices.Length == m.normals.Length, "vertices[{0}] != normals[{1}]", m.vertices.Length, m.normals.Length); offset += MemoryMapUtility.MapVector3ToBytes(m.vertexCount, bytes, offset, stagingFloats, m.normals); } if (hasUV1) { offset += MemoryMapUtility.MapVector2ToBytes(m.vertexCount, bytes, offset, stagingFloats, m.uv); } if (hasUV2) { offset += MemoryMapUtility.MapVector2ToBytes(m.vertexCount, bytes, offset, stagingFloats, m.uv2); } if (hasTangent) { offset += MemoryMapUtility.MapVector4ToBytes(m.vertexCount, bytes, offset, stagingFloats, m.tangents); } lm.verts.Stream = new MemoryStream(bytes, 0, offset, false, true); lm.vertexCount = m.vertexCount; lm.bounds = m.bounds; Profiler.EndSample(); Profiler.EndSample(); Profiler.BeginSample("Write Indices"); var indices = m.triangles; lm.indexCount = indices.Length; var indexSizeInBytes = indices.Length * 2; bytes = new byte[indexSizeInBytes]; var shortIdx = new ushort[indices.Length]; for (var i = 0; i < indices.Length; i++) { shortIdx[i] = (ushort)indices[i]; } Buffer.BlockCopy(shortIdx, 0, bytes, 0, indexSizeInBytes); lm.indices.Stream = new MemoryStream(bytes, 0, indexSizeInBytes, false, true); Profiler.EndSample(); for (var i = 0; i < m.subMeshCount; i++) { var lsm = new LevelSubMesh(); lsm.start = (int)m.GetIndexStart(i); lsm.count = (int)m.GetIndexCount(i); lm.subMeshes.Add(lsm); } if (go.GetComponent <MeshCollider>() && go.GetComponent <MeshCollider>().enabled) { lo.SetMeshCollider(); } if (mr && mr.enabled) { lo.SetMeshRenderer(); // Lightmap settings. lm.lightmapIndex = mr.lightmapIndex; lm.lightmapScaleOffset = mr.lightmapScaleOffset; // Encode materials. foreach (var mrM in mr.sharedMaterials) { lm.materials.Add(mapComp.ResolveMaterialName(mrM.name)); } } lo.mesh = lm; }