Hi there, did some tests with billboard foliage, but getting ~30fps on my craptop rendering nothing but 2400 billboards. Not happy with that at all. I was wondering if maybe there is something I am doing that is sub optimal. Would appreciate it if you experienced people would have a quick look at the code and see if there is anything obviously wrong with it (specifically with regards to frame rate)?

Of course, any tips or criticism welcome.

(grass.png is this: http://www.reinerstilesets.de/3dtextures/billboardgrass0002.png)

```
public class FoliageTest
extends SimpleApplication
{
public static void main(String[] args)
{
new FoliageTest().start();
}
@Override
public void simpleInitApp()
{
flyCam.setMoveSpeed(5f);
Texture grassTexture = assetManager.loadTexture("grass.png");
Material mat = FoliageTest.createFoliageBillboardMaterial(grassTexture, assetManager);
float y = 0;
float density = 0.5f;
for (float ix = 0; ix < 20; ix += density){
for (float iz = 0; iz < 20; iz += density){
float x = ix + (((FastMath.rand.nextFloat() * 2.0f) - 1.0f) * density);
float z = iz + (((FastMath.rand.nextFloat() * 2.0f) - 1.0f) * density);
Node n = FoliageTest.createTriangleBillboardFoliage(mat, x, y, z, 1.2f, 0.9f, 0.25f, 15f);
n.setLocalRotation(new Quaternion().fromAngles(0, FastMath.rand.nextFloat() * 360f, 0));
rootNode.attachChild(n);
}
}
}
public static Material createFoliageBillboardMaterial(Texture texture, AssetManager assetManager)
{
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.setTexture("ColorMap", texture);
mat.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
mat.getAdditionalRenderState().setBlendMode(RenderState.BlendMode.Alpha);
mat.setFloat("AlphaDiscardThreshold", 0.5f);
return mat;
}
public static Node createTriangleBillboardFoliage(Material mat, float x, float y, float z, float width, float height, float overlapRatio, float xRotationDegrees)
{
Node pivot = new Node();
Mesh mesh;
Geometry g;
float triangleHeight = FastMath.sqrt(FastMath.sqr(width) - FastMath.sqr(width / 2.0f));
mesh = new Quad(width, height);
g = new Geometry("a", mesh);
g.setLocalRotation(new Quaternion().fromAngles(xRotationDegrees * FastMath.DEG_TO_RAD * -1f, 60 * FastMath.DEG_TO_RAD, 0));
g.setLocalTranslation(x + ((width / -2.0f) + (width * overlapRatio)), y, z + ((triangleHeight * (1f / 3f)) + (width * overlapRatio / 2.0f)));
g.setMaterial(mat);
g.setQueueBucket(RenderQueue.Bucket.Transparent);
pivot.attachChild(g);
mesh = new Quad(width, height);
g = new Geometry("a", mesh);
g.setLocalRotation(new Quaternion().fromAngles(xRotationDegrees * FastMath.DEG_TO_RAD, 120f * FastMath.DEG_TO_RAD, 0));
g.setLocalTranslation(x + ((width / 2.0f) - (width * overlapRatio)), y, z + ((triangleHeight * (1f / 3f)) + (width * overlapRatio / 2.0f)));
g.setMaterial(mat);
g.setQueueBucket(RenderQueue.Bucket.Transparent);
pivot.attachChild(g);
mesh = new Quad(width, height);
g = new Geometry("a", mesh);
g.setLocalRotation(new Quaternion().fromAngles(xRotationDegrees * FastMath.DEG_TO_RAD * -1f, 180f * FastMath.DEG_TO_RAD, 0));
g.setLocalTranslation(x + (width / 2.0f), y, z + ((triangleHeight * (1f / 3f)) - (width * overlapRatio)));
g.setMaterial(mat);
g.setQueueBucket(RenderQueue.Bucket.Transparent);
pivot.attachChild(g);
return pivot;
}
}
```