I'm working on a sensor project for our search and rescue robots. We have a rotating laser that provides points in space in a cone shape. In one rotation, we see about 25000 unique points.
I would like to create a dynamic 3D scene using these points - culling the older points and showing the newer ones. However, trying to create even 8000 points bombs out jme. Is there a better way to display this many points? Will they be as easy to remove as a point attached to a GameState?
Thanks!
-Jeff Kramer
www.crasar.org
Looking at the console and the exception, it appears to blow up at right around 516 points.
Are you making a new Point object per point? Try using a single Point object with multiple vertices.
Yes, PointBatch is your friend here…
PointBatch? I'll look into it.
Does code like this generate a new Point every time?
for (int i=0; i<NumPoints; i++) {
PointList[i] = new Point("p"+i,vertexes,null,null,null);
gameState.getRootNode().attachChild(PointList[i]);
}
Yes, instead you want to populate your 'vertexes' variable with all your points, then put it in a single Point object.
TestBatchMesh also does something like this (escp. useful if you have several groups of points).
Ah, I was trying to create 80008000 points (each Point call was calling 8000 verticies).
5168000 = 4.128 M points…
Thanks for all the help folks! :) You've won me (and most of my lab) over.
We may have some visualization code to add sometime soon (as in a visualization library).
Thanks!
-Jeff
great to hear! got any nice photos of the robots or something?
Soon! Our laser data will be accurate enough to show millimeter accuracy on things near the laser - expect shots of our faces made of points, etc.
Another question:
I have all these points - can I color them individually?
What's the best method?
I'm currently throwing a ColorRGBA[] to the Point constructor at the same time I send the vertexes. However, this causes the "disco strobe" effect.
Any thoughts?
The ColorRGBA should be fine, you just need to be sure you are assigning the same color value to the same vert each time. Also, eventually you might consider editting the FloatBuffer directly instead of recreating each time passing in the arrays.
doing something like coloring based on distance from laser etc would be fastest if calculated in a shader directly…
another possibility could be to texture the point mesh…in the normal way or with some texture generation used…
It's still strobing. Am I using it wrong?
package jmetest.LaserTest;
import java.util.Random;
import javax.vecmath.*;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.Point;
import com.jme.scene.shape.Box;
import com.jme.scene.state.LightState;
import com.jme.system.DisplaySystem;
import com.jmex.game.StandardGame;
import com.jmex.game.state.DebugGameState;
import com.jmex.game.state.GameStateManager;
/**
* Laser Draw Test
*
* @author Jeff Kramer
*/
public class LaserTest {
static final int NUMPOINTS = 72200;
static StandardGame game;
public static void main(String[] args) throws Exception {
DebugGameState gameState = StartGame("game");
Random r = new Random();
Vector3f[] vertexes = new Vector3f[NUMPOINTS];
ColorRGBA[] colors = new ColorRGBA[NUMPOINTS];
for (int v = 0; v<NUMPOINTS; v++) {vertexes[v] = new Vector3f();} //Set to zero
for (int v = 0; v<NUMPOINTS; v++) {colors[v] = colors[v].white;}
int iTrack = 0;
int RotSize = 5000;
double LaserScanTime = 0.053; //seconds per scan
int LaserValues = 361;
int LaserRange = 10; //in m
double RotRate = 1.5; //Rev/Sec
double RotPush = LaserScanTime*RotRate*RotSize; //points/scan
double RotStep = (RotPush/LaserValues)*((2*Math.PI)/RotSize); //rads/dp
double phi = 0;
float color = 0;
ColorRGBA cWhite = ColorRGBA.white;
double ldist = 0.0;
while (true){
for (int i=0; i<LaserValues; i++) {
ldist = r.nextDouble()*LaserRange;
javax.vecmath.Point3d p3d = AngleToCartesian(ldist, (i*Math.PI)/360, phi);
//System.out.println("X = " + p3d.x + " Y = " + p3d.y + " Z = "+ p3d.z);
vertexes[iTrack].set((float)p3d.x, (float)p3d.y, (float)p3d.z);
color = (float)(ldist/LaserRange);
colors[iTrack].set(color, (float)(color), (float)(color), 1);
//colors[iTrack].set(cWhite);
phi = phi+RotStep;
if (phi >= 2*Math.PI) phi = 0;
if (iTrack < NUMPOINTS-1) {
iTrack++;
} else {
iTrack = 0;
}
//DrawScene(gameState, vertexes, colors);
}
DrawScene(gameState, vertexes, colors);
// Thread.sleep(4000);
}
}
static DebugGameState StartGame (String GameName) {
game = new StandardGame(GameName); //Create the Game
game.start(); //Start the thread
DebugGameState DGS = new DebugGameState(); //create game state
GameStateManager.getInstance().attachChild(DGS); //Attach it
DGS.setActive(true); //Turn it on!
//Box Push
Box box = new Box("TestBox", new Vector3f(), 0.1f, 0.1f, 0.1f); // Create a Box
box.setRandomColors(); // Set random colors on it
box.updateRenderState(); // Update the render state so the colors appear (the game is already running, so this must always be done)
DGS.getRootNode().attachChild(box); // Attach the box to rootNode in DebugGameState
//Lighting Section
LightState lightState = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
lightState.setEnabled(false);
DGS.getRootNode().setRenderState(lightState);
DGS.getRootNode().setLightCombineMode(LightState.REPLACE);
return DGS;
}
static boolean DrawScene(DebugGameState DGS, Vector3f[] vPoints, ColorRGBA[] cColor) {
game.lock();
DGS.getRootNode().detachChildNamed("p");
Point A = new Point("p", vPoints, null, cColor, null);
DGS.getRootNode().attachChild(A);
game.unlock();
return true;
}
static javax.vecmath.Point3d AngleToCartesian(double dRadius, double dLaserAngle, double dRotAngle) {
//System.out.println("In AngleToCartesian");
javax.vecmath.Point3d pCalc = new javax.vecmath.Point3d(dRadius*Math.cos(dLaserAngle), dRadius*Math.sin(dLaserAngle), 0);
Matrix4d mRot = new Matrix4d();
mRot.rotY(dRotAngle);
mRot.transform(pCalc);
//System.out.println(pCalc.x + " " + pCalc.y + " "+ pCalc.z);
return pCalc;
}
}
Thanks for the suggestions - I need to read more about the different parts. :)
-Jeff