【问题标题】:Reading binary PLY file face indices using C#使用 C# 读取二进制 PLY 文件面索引
【发布时间】:2019-11-18 13:57:39
【问题描述】:

我正在使用这个项目读取 .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;
        }

【问题讨论】:

  • 那个解析器不是读取人脸索引,它只是读取顶点信息(x、y、z、r、g、b)。完成后,它会返回,而面部索引未读。

标签: c# mesh ply-file-format


【解决方案1】:

问题是您提供的示例仅期望具有颜色的点云(并且没有面的三角形)。

读取面孔的关键似乎在您在代码中注释的那段代码中。

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

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 意味着你有一个带有顶点数(通常为 3)的 uchar,以及一个带有顶点索引的有符号 int 列表。

因此,您需要更改数据结构以使用 public List&lt;List&lt;Int&gt; &gt; 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;

【讨论】:

    猜你喜欢
    • 2022-01-06
    • 2011-02-03
    • 2017-10-01
    • 2011-09-03
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2015-08-22
    • 2021-03-29
    相关资源
    最近更新 更多