Rendering a Point Cloud inside Unity

May 27th, 2014

Here is a short example of how to render a point cloud using MeshRenderer inside Unity, have in mind that you have a limit of 65k points per mesh, so if you want to render more points, you need to split them.

using UnityEngine;
using System.Collections;


[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer))]
public class PointCloud : MonoBehaviour {

	private Mesh mesh;
	int numPoints = 60000;

	// Use this for initialization
	void Start () {
		mesh = new Mesh();

		GetComponent<MeshFilter>().mesh = mesh;
		CreateMesh();
	}

	void CreateMesh() {
		Vector3[] points = new Vector3[numPoints];
		int[] indecies = new int[numPoints];
		Color[] colors = new Color[numPoints];
		for(int i=0;i<points.Length;++i) {
			points[i] = new Vector3(Random.Range(-10,10), Random.Range (-10,10), Random.Range (-10,10));
			indecies[i] = i;
			colors[i] = new Color(Random.Range(0.0f,1.0f),Random.Range (0.0f,1.0f),Random.Range(0.0f,1.0f),1.0f);
		}

		mesh.vertices = points;
		mesh.colors = colors;
		mesh.SetIndices(indecies, MeshTopology.Points,0);

	}
}

And here is the code for the material’s shader, that will use the vertex color from the mesh:

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 = mul(UNITY_MATRIX_MVP, v.v);
			o.col = v.color;
			
			return o;
		}
		
		float4 frag(VertexOutput o) : COLOR {
			return o.col;
		}

		ENDCG
		} 
	}

}

And this is how you enable GL_VERTEX_PROGRAM_POINT_SIZE and GL_POINT_SMOOTH, so you could set the point size in your shader and have smooth points. Uou must attach this script to your main Camera. The code was found on this thread

#if UNITY_STANDALONE
#define IMPORT_GLENABLE
#endif

using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;

public class EnablePointSize : MonoBehaviour 
{
	const UInt32 GL_VERTEX_PROGRAM_POINT_SIZE = 0x8642;
	const UInt32 GL_POINT_SMOOTH = 0x0B10;
	
	const string LibGLPath =
		#if UNITY_STANDALONE_WIN
		"opengl32.dll";
	#elif UNITY_STANDALONE_OSX
	"/System/Library/Frameworks/OpenGL.framework/OpenGL";
	#elif UNITY_STANDALONE_LINUX
	"libGL";  // Untested on Linux, this may not be correct
	#else
	null;   // OpenGL ES platforms don't require this feature
	#endif
	
	#if IMPORT_GLENABLE
	[DllImport(LibGLPath)]
	public static extern void glEnable(UInt32 cap);
	
	private bool mIsOpenGL;
	
	void Start()
	{
		mIsOpenGL = SystemInfo.graphicsDeviceVersion.Contains("OpenGL");
	}
	
	void OnPreRender()
	{
		if (mIsOpenGL)
			glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
			glEnable(GL_POINT_SMOOTH);
	}
	#endif
}