Download

Saving vertex positions of a skeletal mesh pose; dumping them to file in real-time

Hi everybody! I’m trying to migrate a project of mine from Unity to Unreal, as I think the latter is way more scalable and will greatly simplify the interaction with the non-programming guys in the team. However, the prototype I have in Unity already did some rather finicky stuff which I haven’t been able to reproduce or find information about on the internet.

I have some animated characters (U5 SkinnedMeshRenderer <=> UE4 SkeletalMesh) in the scene. On keypress (or UI buttonpress, doesn’t matter, what’s important is the user prompts it), the animation freezes and through the BakeMesh() method of the Unity SkinnedMeshRenderer I could save a snapshot of that pose. What’s more, I could directly dump the data of the vertices saved in the resulting Mesh onto a file in-game, in a way transparent to the user.

How do I need to go about to reproduce this behaviour? Do I need to extend SkeletalMesh? Or are similar functions already implemented? I couldn’t find anything in the docs… What’s interesting is to reproduce the BakeMesh function, the rest is just a sort of parser-translator over the vertices and other attributes of the StaticMesh.

Here’s the Unity code in case it helps:



   void Update() {
     if (Input.GetKeyDown("p")) {
        SkinnedMeshRenderer smr = characters[currModel].GetComponentInChildren<SkinnedMeshRenderer>();
        string path = Application.dataPath + "/" + smr.name + ".wrl";
        MeshToFile(smr, path);
      }
    }

    public static void MeshToFile(SkinnedMeshRenderer mf, string filename) {
      using (StreamWriter sw = File.CreateText(filename)) {
        sw.Write("#VRML V2.0 utf8
");
        sw.Write(MeshToString(mf, 4000));
        sw.Close();
      }
    }

    public static string MeshToString(SkinnedMeshRenderer mf, float scale) {
        Mesh m = new Mesh();
        mf.BakeMesh(m);
        Material] mats = mf.GetComponent<Renderer>().materials;
        Color col = mats[0].color;
        Vector3 basePosition = mf.transform.position;

        StringBuilder sb = new StringBuilder();

        //shape name
        sb.Append("# " + mf.name + " ");
        sb.Append(string.Format(
            "x:{0} y:{1} z:{2}",
            basePosition.x, basePosition.y, basePosition.z));
        sb.Append("
");

        //vertexs
        sb.Append(
            "Shape {
" +
            "	appearance Appearance {
" +
            "		material Material {
" +
            "		}}
");

        //points
        sb.Append(
            "	geometry IndexedFaceSet {
" +
            "		coord Coordinate {
" +
            "			point  ");
        foreach (Vector3 v in m.vertices) {
            sb.Append(string.Format(
                "{0:F6} {1:F6} {2:F6} ",
                v.x * scale + basePosition.x, v.y * scale + basePosition.y, v.z * scale + basePosition.z));
        }
        sb.Append("]}
");

        //color per Vertex
        sb.Append(
            "		colorPerVertex TRUE
" +
            "		color Color {
" +
            "			color  ");
        for (int i = 0; i < m.vertices.Length; i++) {
            sb.Append(string.Format(
                "{0:F2} {1:F2} {2:F2} ",
                col.r, col.g, col.b));
        }
        sb.Append("]}
");

        //triangles
        sb.Append("		coordIndex  ");
        for (int material = 0; material < m.subMeshCount; material++) {
            int] triangles = m.GetTriangles(material);
            for (int i = 0; i < triangles.Length; i += 3) {
                sb.Append(string.Format(
                    "{0} {1} {2} -1 ",
                    triangles*, triangles[i + 1], triangles[i + 2])
                );
            }
        }
        sb.Append(
            "]}
" +
            "}
");

        return sb.ToString();
    }

Thanks in advance for any pointers!

Did you ever find a solution to this? I’m interested too.