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;
    }