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);}}
更新一下:
代碼上加了個清理,為了重復調用,優化性能
meshNeed.Clear();
還得記得在外面加個try,catch。
大致如下
?
?