因任务需求,需要实现Unity中点云的渲染,同时将点云与模型相结合,达到点云在模型上特定位置的绑定。经相关探索,特此记录。
前言
在Unity中实现点云的渲染可以采用相关的插件,例如PCX插件,可以直接实现在Unity编辑器对PLY格式点云的识别,可直接拖拽到场景中并待颜色显示。但是该插件的缺点在于,相关操作需要预先在编辑器中定义,不能动态的通过脚本控制点云文件的加载与渲染。
为了实现点云在Unity程序中的动态加载与渲染,采用文件读取与Mesh渲染详解和方法。
具体实现思路为:读取点云文件中的明码信息(包括xyz和rgb),储存在C#的容器中,后期通过遍历数据,为Mesh舒服,实现渲染,过程如下。
一、点云文件数据 1.文件有效信息
点云文件的储存形式很多:PCD、PLY、XYZ、XYZRGB、CSV等等,同时文件中点云的储存格式也不尽相同。本文适用于文件中储存的点云信息为明码,如PCD的ascii编码形式或CSV格式,如下图:
PCD-ascii:
CSV:
其他格式的文件也可以进行读取,只需保证Unity在解析文件信息时能够处理掉无用信息,保留点云信息。如PCD文件,前11行信息为PCD的标准格式,可以在PCL程序中进行解析,但在本例中只需要保留点云信息即可。
因此读者在使用时可以采用文件预处理(手动将非有效信息删除)或后处理(通过程序删掉特定行数据)的形式保留有效点云信息,在此不再赘述。
2. rgb信息如上图可见,pcd文件中的rgb值是无符号单值,U:可表示uint8,unit16,uint32,但是我们在Unity中对Mesh的颜色赋值的时候是需要得到RGB的值各是多少,因此需要进行处理:
long nrgb = long.Parse(words[3]);//获取第四列信息 long nr = (nrgb >> 16) & 0x0000ff; long ng = (nrgb >> 8) & 0x0000ff; long nb = (nrgb) & 0x0000ff; Vector3 rgb = new Vector3(nr/255f, ng/255f, nb/255f);//尤其注意,将0-255的数值映射到0-1区间中二、点云渲染
为点云数据创建Mesh:
void CreateMesh()
{
int num = _List[0].Count;
_PointNum = num;
GameObject pointObj = new GameObject();
pointObj.name = "PointCloud";
// 绑定Mesh组件
pointObj.AddComponent();
pointObj.AddComponent();
// 为点云创建新的Mesh
Mesh meshNeed = new Mesh();
Material mat = new Material(Shader.Find("Custom/VertexColor"));
pointObj.GetComponent().mesh = meshNeed;
pointObj.GetComponent().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] = (Vector3)_List[0][i];
indecies[i] = i;
colors[i] = (Color)_List[1][i];
}
meshNeed.vertices = points;
meshNeed.colors = colors;
meshNeed.SetIndices(indecies, MeshTopology.Points, 0);// 设置Mesh的渲染类型为Point
}
其中Shader的代码如下:
Shader "Custom/VertexColor" {
SubShader {
Pass {
LOD 200
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
struct VertexInput {
float4 v : POSITION;
float4 color: COLOR;
};
struct VertexOutput {
float4 pos : SV_POSITION;
float4 col : COLOR;
};
VertexOutput vert(VertexInput v) {
VertexOutput o;
o.pos = UnityObjectToClipPos(v.v);
o.col = v.color;
return o;
}
float4 frag(VertexOutput o) : COLOR {
return o.col;
}
ENDCG
}
}
}
通过以上可以实现对点云的Mesh渲染,但是存在问题:一个Mesh默认可渲染的顶点数最多为65535,可查看API ,当要渲染的点数过多时就会出现渲染一部分的问题,解决思路:
1.循环创建Mesh,一个GameObject包含多个Mesh,单个Mesh包含60000个顶点;
2.API已经说的很清楚,Mesh的索引缓冲区数据类型可更改为32位,最多支持40亿个顶点数据;
Mesh.SetIndexBufferParams(Num, UnityEngine.Rendering.IndexFormat.UInt32);
以上可实现大尺度点云数据在一个Mesh中的渲染。
三、点云数据与模型数据绑定本人的点云数据在Unity程序外通过PCL进行处理,实现点云坐标系和模型坐标系的统一,故在Unity导入点云数据后点云与模型的关系是绑定的。
需要注意的是:PCL中点云坐标系为右手系,Unity模型坐标系为左手系,需要进行左右手的转化。
效果如下:
总结
如上实现Unity中PointCloud的Mesh渲染,欢迎批评指正。
我最大的梦想就是成为你的梦想 .HDarker



