使用 C# 读取二进制 PLY 文件面索引

Reading binary PLY file face indices using C#

我正在使用这个项目读取 .ply 二进制文件: https://github.com/Zarbuz/FileToVox/blob/2064dcf99532e9c22748afb8e1a3755c1e5dfb81/SchematicToVoxCore/Converter/PLYToSchematic.cs

它适用于读取点及其颜色。 但是我不明白如何检索网格面索引列表。

在 ReadDataHeaders 函数中我成功获取了面数:

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

...
}

但我不明白的是如何在函数ReadDataBodyBoundary 中检索网格面索引。 我也不明白 BinaryReader 在这个函数中是如何工作的,它是如何读取网格面顶点索引的每一行二进制形式的。

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

问题是您提供的示例只需要带颜色的点云(而不是面三角形)。

To key to read faces 似乎在您在代码中注释的那段代码中。

我假设你的 ply 文件的 header 是这样的:

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

重要的一行是property list uchar int vertex_indices,这意味着你有一个uchar,其中包含面中的顶点数(通常为3),以及一个带有顶点索引的有符号整数列表。

因此,您需要更改数据结构以使用 public List<List<Int> > faces; 之类的内容存储面孔,并在您拥有 return data; 行的位置添加类似的内容。

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;