Hello all,
I’m setting up LoDs for a custom mesh for the first time.
So far I have:
- Built separate int arrays for different distances;
- Initialize them as VertexBuffers arrays:
[java]VertexBuffer lods[] = new VertexBuffer[3];
lods[0] = new VertexBuffer(Type.Index);
lods[0].setupData(Usage.Dynamic, 1, Format.UnsignedInt, BufferUtils.createIntBuffer(orderAllVertex));[/java]
- Added them to the mesh:
[java]mesh.setLodLevels(lods);[/java]
- Created an LodControl and added it to the geometry:
[java]LodControl lodControl = new LodControl();
lodControl.setDistTolerance(20f);
geom.addControl(lodControl);[/java]
When I run it I always see 4 quads no matter how far I am.
Am I missing a step?
Here is the full code:
[java]package lods;
import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.VertexBuffer.Format;
import com.jme3.scene.VertexBuffer.Type;
import com.jme3.scene.VertexBuffer.Usage;
import com.jme3.scene.control.LodControl;
import com.jme3.scene.debug.Arrow;
import com.jme3.util.BufferUtils;
import java.util.ArrayList;
public class LOD extends SimpleApplication {
public static void main(String[] args) {
LOD app = new LOD();
app.start(); // start the game
}
@Override
public void simpleInitApp() {
createStripNewDataStruct();
attachCoordinateAxes(new Vector3f(0, 0, 0));
}
private boolean createStripNewDataStruct() {
final int vertNumber = 10;
Vector3f[] finalVertices = new Vector3f[vertNumber];
finalVertices[0] = new Vector3f(0, 0, 0);
finalVertices[1] = new Vector3f(1, 0, 0);
finalVertices[2] = new Vector3f(2, 0, 0);
finalVertices[3] = new Vector3f(3, 0, 0);
finalVertices[4] = new Vector3f(4, 0, 0);
finalVertices[5] = new Vector3f(0, 0, 1);
finalVertices[6] = new Vector3f(1, 0, 1);
finalVertices[7] = new Vector3f(2, 0, 1);
finalVertices[8] = new Vector3f(3, 0, 1);
finalVertices[9] = new Vector3f(4, 0, 1);
final int triNumberAllVertex = 8;
int orderAllVertex[] = new int[triNumberAllVertex * 3];
Vector3f pointA[] = new Vector3f[2];
Vector3f pointB[] = new Vector3f[2];
ArrayList<int[]> vertexIndexUpDown;
// all the vertex
for (int v = 0; v < 4; v++) {
pointA[0] = finalVertices[v];
pointA[1] = finalVertices[v + 5];
pointB[0] = finalVertices[v + 1];
pointB[1] = finalVertices[v + 6];
vertexIndexUpDown = calcVertexOrder(pointA, pointB);
for (int i = 0; i < 6; i++) {
switch (vertexIndexUpDown.get(0)) {
case 0:
orderAllVertex = v;
break;
case 1:
orderAllVertex = v + 5;
break;
case 2:
orderAllVertex = v + 1;
break;
case 3:
orderAllVertex = v + 6;
break;
}
}
}
// middle res
final int triNumberMiddleRes = 6;
int orderMiddleRes[] = new int[triNumberMiddleRes * 3];
pointA[0] = finalVertices[0];
pointA[1] = finalVertices[5];
pointB[0] = finalVertices[2];
pointB[1] = finalVertices[7];
vertexIndexUpDown = calcVertexOrder(pointA, pointB);
for (int i = 0; i < 6; i++) {
orderMiddleRes = vertexIndexUpDown.get(0);
}
pointA[0] = finalVertices[2];
pointA[1] = finalVertices[7];
pointB[0] = finalVertices[4];
pointB[1] = finalVertices[9];
vertexIndexUpDown = calcVertexOrder(pointA, pointB);
for (int i = 0; i < 6; i++) {
final int verticeIndex = vertexIndexUpDown.get(0);
switch (verticeIndex) {
case 0:
orderMiddleRes = 2;
break;
case 1:
orderMiddleRes = 7;
break;
case 2:
orderMiddleRes = 4;
break;
case 3:
orderMiddleRes = 9;
break;
}
}
// low res
final int triNumberLowRes = 4;
int orderLowRes[] = new int[triNumberLowRes * 3];
pointA[0] = finalVertices[0];
pointA[1] = finalVertices[5];
pointB[0] = finalVertices[4];
pointB[1] = finalVertices[9];
vertexIndexUpDown = calcVertexOrder(pointA, pointB);
for (int i = 0; i < 6; i++) {
orderMiddleRes = vertexIndexUpDown.get(0);
}
VertexBuffer lods[] = new VertexBuffer[3];
lods[0] = new VertexBuffer(Type.Index);
lods[0].setupData(Usage.Dynamic, 1, Format.UnsignedInt, BufferUtils.createIntBuffer(orderAllVertex));
lods[1] = new VertexBuffer(Type.Index);
lods[1].setupData(Usage.Dynamic, 1, Format.UnsignedInt, BufferUtils.createIntBuffer(orderMiddleRes));
lods[2] = new VertexBuffer(Type.Index);
lods[2].setupData(Usage.Dynamic, 1, Format.UnsignedInt, BufferUtils.createIntBuffer(orderLowRes));
// with lod
createMesh(finalVertices, orderAllVertex, "upside", ColorRGBA.Yellow, lods);
return true;
}
private ArrayList<int[]> calcVertexOrder(Vector3f wingsA[], Vector3f wingsB[]) {
Vector3f[] currVertices = new Vector3f[4];
// Set the current array with the wing points of this and the past point
currVertices[0] = wingsA[0];
currVertices[1] = wingsA[1];
currVertices[2] = wingsB[0];
currVertices[3] = wingsB[1];
// Calculate how to put them to create one mesh clockwise and another counter clockwise
return orderVertexIndexes(currVertices);
}
private ArrayList<int[]> orderVertexIndexes(Vector3f[] vertices) {
boolean shortest12 = is12ShortestThan03(vertices);
int common2ndWingPDown, common1stWingPDown, opposite2ndWingPDown, opposite1stWingPDown;
opposite1stWingPDown = opposite2ndWingPDown = common1stWingPDown = common2ndWingPDown = -1;
if (shortest12) {
common2ndWingPDown = 2;
opposite2ndWingPDown = 3;
common1stWingPDown = 1;
opposite1stWingPDown = 0;
} else { // shortest
common2ndWingPDown = 3;
opposite2ndWingPDown = 2;
common1stWingPDown = 0;
opposite1stWingPDown = 1;
}
int[] indexesDown = new int[6];
int[] indexesUp = new int[6];
// First triangle
boolean isCCW_Down = isCounterClock(vertices[opposite1stWingPDown], vertices[common1stWingPDown], vertices[common2ndWingPDown]);
indexesDown[0] = opposite1stWingPDown;
indexesUp[0] = opposite1stWingPDown;
if (isCCW_Down) {
indexesDown[1] = common1stWingPDown;
indexesDown[2] = common2ndWingPDown;
// Second triangle
indexesDown[3] = common2ndWingPDown;
indexesDown[4] = common1stWingPDown;
indexesDown[5] = opposite2ndWingPDown;
// - Up
indexesUp[1] = common2ndWingPDown;
indexesUp[2] = common1stWingPDown;
// Second triangle
indexesUp[3] = common1stWingPDown;
indexesUp[4] = common2ndWingPDown;
indexesUp[5] = opposite2ndWingPDown;
} else {
indexesDown[1] = common2ndWingPDown;
indexesDown[2] = common1stWingPDown;
// Second triangle
indexesDown[3] = common1stWingPDown;
indexesDown[4] = common2ndWingPDown;
indexesDown[5] = opposite2ndWingPDown;
// - Up
indexesUp[1] = common1stWingPDown;
indexesUp[2] = common2ndWingPDown;
// Second triangle
indexesUp[3] = common2ndWingPDown;
indexesUp[4] = common1stWingPDown;
indexesUp[5] = opposite2ndWingPDown;
}
ArrayList<int[]> vertexIndexUpDown = new ArrayList<int[]>(2);
vertexIndexUpDown.add(0, indexesUp);
vertexIndexUpDown.add(1, indexesDown);
return vertexIndexUpDown;
}
private boolean isCounterClock(Vector3f p1, Vector3f p2, Vector3f p3) {
Vector3f normal = FastMath.computeNormal(p1, p2, p3);
// the normal vector for the downwards face must always have negative y
if (normal.y <= 0f) {
return true;
} else {
return false;
}
}
private boolean is12ShortestThan03(Vector3f[] vertices) {
float distances[] = new float[2];
distances[0] = vertices[1].distance(vertices[2]); // distBC
distances[1] = vertices[0].distance(vertices[3]); // distAD
if (distances[0] > distances[1]) {
return false;
} else {
return true;
}
}
protected void attachCoordinateAxes(Vector3f pos) {
Arrow arrow = new Arrow(Vector3f.UNIT_X.multLocal(10));
arrow.setLineWidth(4); // make arrow thicker
putShape(arrow, ColorRGBA.Red).setLocalTranslation(pos);
arrow = new Arrow(Vector3f.UNIT_Y.multLocal(10));
arrow.setLineWidth(4); // make arrow thicker
putShape(arrow, ColorRGBA.Green).setLocalTranslation(pos);
arrow = new Arrow(Vector3f.UNIT_Z.multLocal(10));
arrow.setLineWidth(4); // make arrow thicker
putShape(arrow, ColorRGBA.Blue).setLocalTranslation(pos);
}
protected Geometry putShape(Mesh shape, ColorRGBA color) {
Geometry g = new Geometry("coordinate axis", shape);
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.getAdditionalRenderState().setWireframe(true);
mat.setColor("Color", color);
g.setMaterial(mat);
rootNode.attachChild(g);
return g;
}
protected Geometry createMesh(Vector3f[] vertices, int[] vertexIndex, String meshName, ColorRGBA color,
VertexBuffer[] lod) {
Material mat;
Geometry geom;
Mesh mesh = new Mesh();
// For downside
mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
mesh.setBuffer(Type.Index, 3, BufferUtils.createIntBuffer(vertexIndex));
mesh.updateBound();
geom = new Geometry(meshName, mesh);
if (lod != null) {
mesh.setLodLevels(lod);
LodControl lodControl = new LodControl();
lodControl.setDistTolerance(20f);
geom.addControl(lodControl);
}
mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
mat.getAdditionalRenderState().setWireframe(true);
mat.setColor("Color", ColorRGBA.Red);
geom.setMaterial(mat);
rootNode.attachChild(geom);
return geom;
}
}[/java]