static unsafe InputAccess GetInputAccess(PointElementName name, List <PointElement> elements, byte *data, int stride) { foreach (var element in elements) { if (element.Name == name) { if (element.Type == PointElementType.Float || element.Type == PointElementType.Double) { int elementSize = PointElement.GetSize(element.Type); return(new InputAccess() { Size = elementSize, Stride = stride, Data = data + element.Offset }); } else { throw new Exception($"Point Cloud {name} field has unsupported type {element.Type}"); } } } throw new Exception($"Point Cloud does not have {name} field"); }
PointCloudData ImportPly(AssetImportContext context) { using (var file = MemoryMappedFile.CreateFromFile(context.assetPath, FileMode.Open)) { long dataOffset; long dataCount = 0; int elementOffset = 0; var properties = new List <string>(); var elements = new List <PointElement>(); using (var view = file.CreateViewStream(0, 4096, MemoryMappedFileAccess.Read)) { var buffer = new byte[4096]; int length = view.Read(buffer, 0, buffer.Length); using (var stream = new MemoryStream(buffer, 0, length, false)) { var byteLine = new byte[128]; bool first = true; while (true) { int byteCount = stream.Read(byteLine, 0, byteLine.Length); int index = -1; for (int i = 0; i < byteCount; i++) { if (byteLine[i] == '\n' || byteLine[i] == '\r') { index = i; break; } } if (index == -1) { throw new Exception("Bad PLY file"); } var line = Encoding.ASCII.GetString(byteLine, 0, index); byte next = byteLine[index + 1]; stream.Position -= byteLine.Length - (index + (next == '\r' || next == '\n' ? 2 : 1)); if (first && line != "ply") { throw new Exception("Bad PLY file format"); } first = false; if (line.StartsWith("format")) { var format = line.Split(new[] { ' ' }); if (format[1] != "binary_little_endian" || format[2] != "1.0") { throw new Exception($"Unsupported PLY format: {line}"); } } else if (line.StartsWith("property")) { var props = line.Split(new[] { ' ' }, 3); if (props[1] != "list") { PointElementType?type = null; PointElementName?name = null; if (props[1] == "uint8") { type = PointElementType.Byte; } if (props[1] == "float32") { type = PointElementType.Float; } if (props[1] == "float64") { type = PointElementType.Double; } if (props[1] == "uchar") { type = PointElementType.Byte; } if (props[1] == "float") { type = PointElementType.Float; } if (props[1] == "double") { type = PointElementType.Double; } if (props[2] == "x") { name = PointElementName.X; } if (props[2] == "y") { name = PointElementName.Y; } if (props[2] == "z") { name = PointElementName.Z; } if (props[2] == "red") { name = PointElementName.R; } if (props[2] == "green") { name = PointElementName.G; } if (props[2] == "blue") { name = PointElementName.B; } if (props[2] == "intensity") { name = PointElementName.I; } if (props[2] == "scalar_intensity") { name = PointElementName.I; } if (!type.HasValue) { throw new Exception($"PLY file has unsupported property type {props[1]}"); } if (name.HasValue) { elements.Add(new PointElement() { Type = type.Value, Name = name.Value, Offset = elementOffset }); } elementOffset += PointElement.GetSize(type.Value); } } else if (line.StartsWith("element vertex")) { var vertex = line.Split(new[] { ' ' }, 3); dataCount = long.Parse(vertex[2]); } else if (line.StartsWith("end_header")) { break; } } dataOffset = stream.Position; } } int dataStride = elementOffset; using (var view = file.CreateViewAccessor(dataOffset, dataCount * dataStride, MemoryMappedFileAccess.Read)) { return(ImportPoints(context, view, dataCount, dataStride, elements)); } } }