unity pcd 二进制版 简单显示文件对象(单色)
unity Point Cloud Viewer and Tool 那个插件不支持pcd二进制,而且网上到处都是AI
我恨这种AI滥用,提供不了一点价值
好了,言归正传
可以在Point Cloud Viewer and Tool这个插件报错地方转用这个代码,具体咋结合请自行研究。
部分参考:
Unity PointCloud开发:Mesh渲染点云_unity 点云特效-CSDN博客
步骤大致为
按行读取文件
发现是二进制文件
解码,计算出是三维坐标点的位置
然后直接实例化对象
为了保证性能,用了上面链接的方案,这样不用第三方库,也能兼容统信和多种平台
在一个空对象上直接挂载代码,作者设置如下
全代码+注释如下:
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;public class PCDReader :UnitySingleton<PCDReader>
{public string filePath = "文件路径"; // PCD文件路径,需放置在Unity工程中public GameObject _obj;void Start(){LoadPCD(filePath);}public void LoadPCD(string path)//FileStream{/*if (!File.Exists(path)){Debug.LogError("文件不存在:" + path);return;}*/// 读取文件流using (FileStream stream=new FileStream(path, FileMode.Open))using (BinaryReader reader = new BinaryReader(stream)){// Step 1: 解析头部(ASCII格式)Dictionary<string, string> header = new Dictionary<string, string>();string line;while (true){line = ReadLine(reader); // 自定义方法读取一行ASCII文本if (line == null || line.StartsWith("DATA binary"))break;string[] parts = line.Split(' ');if (parts.Length >= 2){header[parts[0]] = parts[1];}}// 验证头部关键字段if (!header.ContainsKey("FIELDS") || !header.ContainsKey("POINTS") || !header.ContainsKey("SIZE")){Debug.LogError("头部信息不完整");}// 提取元数据string[] fields = header["FIELDS"].Split(' ');int pointCount = int.Parse(header["POINTS"]);string[] sizes = header["SIZE"].Split(' ');List<Vector3> points = new List<Vector3>(); // 存储点坐标List<Color> colors = new List<Color>(); // 存储点颜色(如果存在rgb字段)// 计算每个点的大小(基于SIZE和COUNT)int pointSize = 0;foreach (string size in sizes){pointSize += int.Parse(size); // SIZE每个值通常是4(字节)}// Step 2: 读取二进制数据部分for (int i = 0; i < pointCount; i++){// 读取坐标(假设前三个字段是x,y,z)float x = reader.ReadSingle(); // 4字节浮点数float y = reader.ReadSingle();float z = reader.ReadSingle();points.Add(new Vector3(x, y, z));// 如果存在rgb字段,读取并转换为Unity颜色/*if (fields.Length >= 4 && fields[3] == "rgb"){uint rgb = reader.ReadUInt32(); // rgb通常以UInt32存储float r = ((rgb >> 16) & 0xFF) / 255.0f;float g = ((rgb >> 8) & 0xFF) / 255.0f;float b = (rgb & 0xFF) / 255.0f;colors.Add(new Color(r, g, b));}*/// 跳过其他字段(如有)int remainingSize = pointSize;//- 12 - 4; // 减去xyz(12字节)和rgb(4字节)reader.ReadBytes(remainingSize);}// Step 3: 在Unity中创建点云对象CreatePointCloud(points, colors);//return points;}}// 辅助方法:从二进制流读取一行ASCII文本private string ReadLine(BinaryReader reader){List<byte> bytes = new List<byte>();byte nextByte;while (reader.BaseStream.Position < reader.BaseStream.Length){nextByte = reader.ReadByte();if (nextByte == '\n') // 换行符结束行break;bytes.Add(nextByte);}return System.Text.Encoding.ASCII.GetString(bytes.ToArray());}// 辅助方法:创建点云GameObject(使用Mesh)private void CreatePointCloud(List<Vector3> points, List<Color> colors){GameObject pointCloud = _obj;/*new GameObject("PointCloud");Mesh mesh = new Mesh();// mesh.vertices = points.ToArray();// 设置颜色(如果存在)/*if (colors.Count == points.Count){mesh.colors = colors.ToArray();}#1#// 创建MeshRenderer和MeshFilterMeshFilter meshFilter = pointCloud.AddComponent<MeshFilter>();MeshRenderer meshRenderer = pointCloud.AddComponent<MeshRenderer>();meshFilter.mesh = mesh;// 使用默认材质(可通过Unity材质自定义)meshRenderer.material = new Material(Shader.Find("Standard"));*/CreateMesh(points.Count,points);/*for (int i = 0; i < points.Count; i++){GameObject _obj=GameObject.Instantiate(pointCloud);_obj.transform.position = points[i];}*/Debug.Log("点云加载完成,点数: " + points.Count);}public Mesh meshNeed;void CreateMesh(int num,List<Vector3> point){int _PointNum = num;GameObject pointObj = new GameObject();pointObj.name = "PointCloud";// 绑定Mesh组件pointObj.AddComponent<MeshFilter>();pointObj.AddComponent<MeshRenderer>();// 为点云创建新的MeshMaterial mat = new Material(Shader.Find("Custom/VertexColor"));pointObj.GetComponent<MeshFilter>().mesh = meshNeed;pointObj.GetComponent<MeshRenderer>().material = mat;Vector3[] points = new Vector3[num];Color[] colors = new Color[num];int[] indecies = new int[num];for (int i = 0; i < num; ++i){points[i] = point[i];indecies[i] = i;colors[i] = Color.white;}meshNeed.vertices = points;meshNeed.colors = colors;meshNeed.SetIndices(indecies, MeshTopology.Points, 0);// 设置Mesh的渲染类型为PointmeshNeed.SetIndexBufferParams(num, UnityEngine.Rendering.IndexFormat.UInt32);}}