Search code examples
c#meshply-file-format

Reading binary PLY file face indices using C#


I am reading .ply binary file using this project: https://github.com/Zarbuz/FileToVox/blob/2064dcf99532e9c22748afb8e1a3755c1e5dfb81/SchematicToVoxCore/Converter/PLYToSchematic.cs

It works for reading points and their colors. But I do not understand how to retrieve the list of mesh faces indices.

In the function ReadDataHeaders I successuflly retrieve the number of faces:

 private static DataHeader ReadDataHeader(StreamReader reader) {
 ...
                if (col[0] == "element") {
                    if (col[1] == "vertex") {
                        data.vertexCount = Convert.ToInt32(col[2]);
                        skip = false;
                    } else if (col[1] == "face") {
                        data.faceCount = Convert.ToInt32(col[2]);
                        skip = false;
                    } else {
                        // Don't read elements other than vertices.
                        skip = true;
                    }
                }

...
}

But what I do not understand is how retrieve the mesh face indices in the function ReadDataBodyBoundary. I do not also understand how the BinaryReader works in this function, how does it reads the each line of binary form for mesh faces vertex indices.

 private static DataBody ReadDataBodyBinary(DataHeader header, BinaryReader reader) {
            DataBody data = new DataBody(header.vertexCount,header.faceCount);

            float x = 0, y = 0, z = 0;
            byte r = 255, g = 255, b = 255, a = 255;
            int f0 = 0, f1 = 0, f2 = 0;

            //for(int i = 0; i < header.faceCount; i++) {
            //    //foreach(var face in )
            //    int faceVertex = reader.ReadInt32();
            //    Console.WriteLine();
            //}
            //reader.BaseStream.Position = readCount;
            Console.WriteLine("Number of properties:   " + header.properties.Count().ToString());
            for (int i = 0; i < header.vertexCount; i++) {
                foreach (DataProperty prop in header.properties) {//iterate six properties
                    //Console.WriteLine(prop.ToString());
                    switch (prop) {
                        case DataProperty.R8:
                        r = reader.ReadByte();
                        break;
                        case DataProperty.G8:
                        g = reader.ReadByte();
                        break;
                        case DataProperty.B8:
                        b = reader.ReadByte();
                        break;
                        case DataProperty.A8:
                        a = reader.ReadByte();
                        break;

                        case DataProperty.R16:
                        r = (byte)(reader.ReadUInt16() >> 8);
                        break;
                        case DataProperty.G16:
                        g = (byte)(reader.ReadUInt16() >> 8);
                        break;
                        case DataProperty.B16:
                        b = (byte)(reader.ReadUInt16() >> 8);
                        break;
                        case DataProperty.A16:
                        a = (byte)(reader.ReadUInt16() >> 8);
                        break;

                        case DataProperty.SingleX:
                        x = reader.ReadSingle();
                        break;
                        case DataProperty.SingleY:
                        y = reader.ReadSingle();
                        break;
                        case DataProperty.SingleZ:
                        z = reader.ReadSingle();
                        break;

                        case DataProperty.DoubleX:
                        x = (float)reader.ReadDouble();
                        break;
                        case DataProperty.DoubleY:
                        y = (float)reader.ReadDouble();
                        break;
                        case DataProperty.DoubleZ:
                        z = (float)reader.ReadDouble();
                        break;

                        case DataProperty.Data8:
                        reader.ReadByte();
                        break;
                        case DataProperty.Data16:
                        reader.BaseStream.Position += 2;
                        break;
                        case DataProperty.Data32:
                        reader.BaseStream.Position += 4;
                        break;
                        case DataProperty.Data64:
                        reader.BaseStream.Position += 8;
                        break;
                    }
                }

                data.AddPoint(x, y, z, r, g, b);
            }

            return data;
        }

Solution

  • The problem is that the example you provide only expect cloud of point with color (and no triangles of faces).

    To key to read faces seems to be in that piece of code you have commented in your code.

    I am supposing that the header of your ply file is something like this:

    ply
    format binary_little_endian 1.0
    element vertex 326
    property float x
    property float y
    property float z
    property uchar r
    property uchar g
    property uchar b
    property uchar a
    element face 595
    property list uchar int vertex_indices
    end_header
    

    The important line is that property list uchar int vertex_indices meaning that you have an uchar with the number of vertex in the face (usually 3), and a list of signed int with the vertex indices.

    So you need to change the data structure to store faces with something like public List<List<Int> > faces; and add something similar to this where you have your return data; line.

    for(int i = 0; i < header.faceCount; i++) {
        byte numVertex = reader.ReadByte(); //Read one uchar. Usually 3.
        List<int> indices = new List<int>();
        for(byte j = 0; j < numVertex; j++) {
           indices.Add(reader.ReadInt());   //Read one int and store in the list
        }
        data.faces.Add(indices);                 //Store the face
    }
    
    return data;