How to render a 3d point cloud?

Hi, my question is about displaying 3d point clouds with JME. Lets say i have a point cloud which 3d positions and maybe also a color for each point. I thought it would be a good idea to display this cloud via the ParticleEmitter class using a custom emitter shape (i took a look at the EmitterBoxShape class and it looks simple enough to create my own with fixed positions for each particle instead of random ones). The point cloud has a size of around 5000 to 50.000 points and I would like to display it on an Android phone. Is there a more performant approach or do you think its fine to do it like this? Or should i maybe implement my own class similar to the ParticleEmitter, or maybe I don’t need all that at all and its possible to render geometry with single points out of the box?

no one has any tipps for me? :S

Well the mos straightforward way is to create a own mesh with pointmode (assuming la points are the same(, sizewise)). However if you can display all 50k on an android depends very much on the hardware and the firmeware version/bugs. At least for a desktop computer you can go into several million that way so it might be realsitic enough with 50k

1 Like
@Empire Phoenix said: Well the mos straightforward way is to create a own mesh with pointmode (assuming la points are the same(, sizewise)). However if you can display all 50k on an android depends very much on the hardware and the firmeware version/bugs. At least for a desktop computer you can go into several million that way so it might be realsitic enough with 50k

ok thanks, i will try this. maybe there is a way to render only the points close to the camera via a octree or something similar. i had the impression that the ParticleEmitter did not always render 100% of all particles but only the ones which were visible to the user, or am I wrong?

@simon.heinen said: ok thanks, i will try this. maybe there is a way to render only the points close to the camera via a octree or something similar. i had the impression that the ParticleEmitter did not always render 100% of all particles but only the ones which were visible to the user, or am I wrong?

It renders all of them… so you must have something crossed in your memory. :slight_smile:

@pspeed said: It renders all of them... so you must have something crossed in your memory. :)

It works all fine now on the desktop but on the phone the size of the points is not rendered correctly and the points have from any distance always the size 1. Maybe this is a shader problem? I tried to set the material settings by hand and also via the mesh, both works on the desktop:

	Material mat = new Material(assetManager,
			"Common/MatDefs/Misc/Particle.j3md");
	mat.getAdditionalRenderState().setBlendMode(BlendMode.Off);
	// mat.getAdditionalRenderState().setPointSprite(true);
	// mat.setBoolean("PointSprite", true);
	// mat.setFloat("Quadratic", 0.25f);

	m = new Mesh();
	m.setMode(Mode.Points);
	m.setPointSize(20);
	m.setStatic();

	g = new Geometry("Point Cloud", m);
	g.setShadowMode(ShadowMode.Off);
	g.setQueueBucket(Bucket.Opaque);
	g.setMaterial(mat);
	attachChild(g);

It could be that your phone doesn’t support point sprites, I guess. I’m not familiar with Android limitations, really.

@pspeed said: It could be that your phone doesn't support point sprites, I guess. I'm not familiar with Android limitations, really.

would the logs tell me something if the phone does not support this feature? i mean point sprites are supported otherwise I would not the the point cloud rihgt? its just the size of the pixels which is not set corretly. In this code example the point size is also set so it seems to be possible with opengl es 2 but maybe its realy the Samsung S3 which has problems…

Someone more familiar with Android may have to answer but I know even on desktop sometimes GPUs enforce a maximum sprite size (a lot of times 64 pixels but it is a ‘thing’). JME provides no way currently to query the maximum sprite size.

OpenGL ES 2.0 only supports point sprites. You cannot comment out the line “mat.setBoolean(“PointSprite”, true)”

@Momoko_Fan said: OpenGL ES 2.0 only supports point sprites. You cannot comment out the line "mat.setBoolean(“PointSprite”, true)"

I tested it with both PointSprite used and also with “m.setPointSize(pointSize);” because i found this java doc at the setPointSize method:

Set the size of points for meshes of mode Mode.Points. The point size is specified as on-screen pixels, the default value is 1.0. The point size does nothing if point sprite render state is enabled, in that case, the vertex shader must specify the point size by writing to gl_PointSize.

Both ways work correctly on the desktop and do not work on the phone (the points are displayed but their size is always 1 pixel no matter how close i am to the points

Here is the complete code of the point cloud node i created:

[java]
public class PCN extends Node {

private static final boolean USE_INDIVIDUAL_POINT_SIZES = false;

private final Mesh m;
private final Geometry g;

public PCN(AssetManager assetManager) {
	Material mat = new Material(assetManager,
			"Common/MatDefs/Misc/Particle.j3md");
	mat.getAdditionalRenderState().setBlendMode(BlendMode.Off);

	if (USE_INDIVIDUAL_POINT_SIZES) {
		mat.getAdditionalRenderState().setPointSprite(true);
		mat.setBoolean("PointSprite", true);
		mat.setFloat("Quadratic", 1f);
	}

	m = new Mesh();
	m.setMode(Mode.Points);
	m.setStatic();

	g = new Geometry("Point Cloud", m);
	g.setShadowMode(ShadowMode.Off);
	g.setQueueBucket(Bucket.Opaque);
	g.setMaterial(mat);
	attachChild(g);
}

public void setBuffers(FloatBuffer pointCoordinates3d,
		FloatBuffer colorsRGBA, float pointSize) {
	FloatBuffer pixelSizes = null;
	if (USE_INDIVIDUAL_POINT_SIZES) {
		pixelSizes = PCN.newPixelSizeBuffer(10,
				pointCoordinates3d.limit() / 3);
	}
	setBuffers(pointCoordinates3d, colorsRGBA, pixelSizes, pointSize);
}

public void setBuffers(FloatBuffer pointCoordinates3d,
		FloatBuffer colorsRGBA, FloatBuffer pixelSizes, float pointSize) {
	m.setBuffer(VertexBuffer.Type.Position, 3, pointCoordinates3d);
	m.setBuffer(VertexBuffer.Type.Color, 4, colorsRGBA);
	if (USE_INDIVIDUAL_POINT_SIZES) {
		m.setBuffer(VertexBuffer.Type.Size, 1, pixelSizes);
	} else {
		m.setPointSize(pointSize);
	}
	m.updateBound();
	g.updateModelBound();
	updateModelBound();
} 

[/java]

When you want to use point sprites (rather than just points) then you need to specify a texture for the sprites.

Take a look again at the TestPointCloud (or whatever) as it uses point sprites and not just points.

@simon.heinen said: I tested it with both PointSprite used and also with "m.setPointSize(pointSize);" because i found this java doc at the setPointSize method:

Both ways work correctly on the desktop and do not work on the phone (the points are displayed but their size is always 1 pixel no matter how close i am to the points

GLES does not mandate a minimum/maximum pixel size on point sprites, that is HW-dependant and many phones only support 1 as maximum size. Hard to find a definite source since there is no defined maximum size (i.e. not written in the spec that it is allowed to be 1) but stack overflow has many questions about this.