|
@@ -50,6 +50,7 @@ import com.jme3.scene.mesh.IndexBuffer;
|
|
import com.jme3.terrain.geomipmap.TerrainQuad.LocationHeight;
|
|
import com.jme3.terrain.geomipmap.TerrainQuad.LocationHeight;
|
|
import com.jme3.terrain.geomipmap.lodcalc.util.EntropyComputeUtil;
|
|
import com.jme3.terrain.geomipmap.lodcalc.util.EntropyComputeUtil;
|
|
import com.jme3.util.BufferUtils;
|
|
import com.jme3.util.BufferUtils;
|
|
|
|
+import com.jme3.util.clone.Cloner;
|
|
import java.io.IOException;
|
|
import java.io.IOException;
|
|
import java.nio.Buffer;
|
|
import java.nio.Buffer;
|
|
import java.nio.FloatBuffer;
|
|
import java.nio.FloatBuffer;
|
|
@@ -65,18 +66,18 @@ import java.util.List;
|
|
* That uses a geo-mipmapping algorithm to change the index buffer of the mesh.
|
|
* That uses a geo-mipmapping algorithm to change the index buffer of the mesh.
|
|
* The mesh is a triangle strip. In wireframe mode you might notice some strange lines, these are degenerate
|
|
* The mesh is a triangle strip. In wireframe mode you might notice some strange lines, these are degenerate
|
|
* triangles generated by the geoMipMap algorithm and can be ignored. The video card removes them at almost no cost.
|
|
* triangles generated by the geoMipMap algorithm and can be ignored. The video card removes them at almost no cost.
|
|
- *
|
|
|
|
|
|
+ *
|
|
* Each patch needs to know its neighbour's LOD so it can seam its edges with them, in case the neighbour has a different
|
|
* Each patch needs to know its neighbour's LOD so it can seam its edges with them, in case the neighbour has a different
|
|
* LOD. If this doesn't happen, you will see gaps.
|
|
* LOD. If this doesn't happen, you will see gaps.
|
|
- *
|
|
|
|
|
|
+ *
|
|
* The LOD value is most detailed at zero. It gets less detailed the higher the LOD value until you reach maxLod, which
|
|
* The LOD value is most detailed at zero. It gets less detailed the higher the LOD value until you reach maxLod, which
|
|
* is a mathematical limit on the number of times the 'size' of the patch can be divided by two. However there is a -1 to that
|
|
* is a mathematical limit on the number of times the 'size' of the patch can be divided by two. However there is a -1 to that
|
|
* for now until I add in a custom index buffer calculation for that max level, the current algorithm does not go that far.
|
|
* for now until I add in a custom index buffer calculation for that max level, the current algorithm does not go that far.
|
|
- *
|
|
|
|
- * You can supply a LodThresholdCalculator for use in determining when the LOD should change. It's API will no doubt change
|
|
|
|
- * in the near future. Right now it defaults to just changing LOD every two patch sizes. So if a patch has a size of 65,
|
|
|
|
|
|
+ *
|
|
|
|
+ * You can supply a LodThresholdCalculator for use in determining when the LOD should change. It's API will no doubt change
|
|
|
|
+ * in the near future. Right now it defaults to just changing LOD every two patch sizes. So if a patch has a size of 65,
|
|
* then the LOD changes every 130 units away.
|
|
* then the LOD changes every 130 units away.
|
|
- *
|
|
|
|
|
|
+ *
|
|
* @author Brent Owens
|
|
* @author Brent Owens
|
|
*/
|
|
*/
|
|
public class TerrainPatch extends Geometry {
|
|
public class TerrainPatch extends Geometry {
|
|
@@ -118,7 +119,7 @@ public class TerrainPatch extends Geometry {
|
|
super("TerrainPatch");
|
|
super("TerrainPatch");
|
|
setBatchHint(BatchHint.Never);
|
|
setBatchHint(BatchHint.Never);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public TerrainPatch(String name) {
|
|
public TerrainPatch(String name) {
|
|
super(name);
|
|
super(name);
|
|
setBatchHint(BatchHint.Never);
|
|
setBatchHint(BatchHint.Never);
|
|
@@ -221,7 +222,7 @@ public class TerrainPatch extends Geometry {
|
|
public FloatBuffer getHeightmap() {
|
|
public FloatBuffer getHeightmap() {
|
|
return BufferUtils.createFloatBuffer(geomap.getHeightArray());
|
|
return BufferUtils.createFloatBuffer(geomap.getHeightArray());
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public float[] getHeightMap() {
|
|
public float[] getHeightMap() {
|
|
return geomap.getHeightArray();
|
|
return geomap.getHeightArray();
|
|
}
|
|
}
|
|
@@ -256,7 +257,7 @@ public class TerrainPatch extends Geometry {
|
|
idxB = geomap.writeIndexArrayLodVariable(pow, (int) Math.pow(2, utp.getRightLod()), (int) Math.pow(2, utp.getTopLod()), (int) Math.pow(2, utp.getLeftLod()), (int) Math.pow(2, utp.getBottomLod()), totalSize);
|
|
idxB = geomap.writeIndexArrayLodVariable(pow, (int) Math.pow(2, utp.getRightLod()), (int) Math.pow(2, utp.getTopLod()), (int) Math.pow(2, utp.getLeftLod()), (int) Math.pow(2, utp.getBottomLod()), totalSize);
|
|
else
|
|
else
|
|
idxB = geomap.writeIndexArrayLodDiff(pow, right, top, left, bottom, totalSize);
|
|
idxB = geomap.writeIndexArrayLodDiff(pow, right, top, left, bottom, totalSize);
|
|
-
|
|
|
|
|
|
+
|
|
Buffer b;
|
|
Buffer b;
|
|
if (idxB.getBuffer() instanceof IntBuffer)
|
|
if (idxB.getBuffer() instanceof IntBuffer)
|
|
b = (IntBuffer)idxB.getBuffer();
|
|
b = (IntBuffer)idxB.getBuffer();
|
|
@@ -277,14 +278,14 @@ public class TerrainPatch extends Geometry {
|
|
return store.set(getMesh().getFloatBuffer(Type.TexCoord).get(idx*2),
|
|
return store.set(getMesh().getFloatBuffer(Type.TexCoord).get(idx*2),
|
|
getMesh().getFloatBuffer(Type.TexCoord).get(idx*2+1) );
|
|
getMesh().getFloatBuffer(Type.TexCoord).get(idx*2+1) );
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
public float getHeightmapHeight(float x, float z) {
|
|
public float getHeightmapHeight(float x, float z) {
|
|
if (x < 0 || z < 0 || x >= size || z >= size)
|
|
if (x < 0 || z < 0 || x >= size || z >= size)
|
|
return 0;
|
|
return 0;
|
|
int idx = (int) (z * size + x);
|
|
int idx = (int) (z * size + x);
|
|
return getMesh().getFloatBuffer(Type.Position).get(idx*3+1); // 3 floats per entry (x,y,z), the +1 is to get the Y
|
|
return getMesh().getFloatBuffer(Type.Position).get(idx*3+1); // 3 floats per entry (x,y,z), the +1 is to get the Y
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Get the triangle of this geometry at the specified local coordinate.
|
|
* Get the triangle of this geometry at the specified local coordinate.
|
|
* @param x local to the terrain patch
|
|
* @param x local to the terrain patch
|
|
@@ -306,7 +307,7 @@ public class TerrainPatch extends Geometry {
|
|
}
|
|
}
|
|
|
|
|
|
protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) {
|
|
protected void setHeight(List<LocationHeight> locationHeights, boolean overrideHeight) {
|
|
-
|
|
|
|
|
|
+
|
|
for (LocationHeight lh : locationHeights) {
|
|
for (LocationHeight lh : locationHeights) {
|
|
if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size)
|
|
if (lh.x < 0 || lh.z < 0 || lh.x >= size || lh.z >= size)
|
|
continue;
|
|
continue;
|
|
@@ -317,7 +318,7 @@ public class TerrainPatch extends Geometry {
|
|
float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1);
|
|
float h = getMesh().getFloatBuffer(Type.Position).get(idx*3+1);
|
|
geomap.getHeightArray()[idx] = h+lh.h;
|
|
geomap.getHeightArray()[idx] = h+lh.h;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
|
|
FloatBuffer newVertexBuffer = geomap.writeVertexArray(null, stepScale, false);
|
|
@@ -351,7 +352,7 @@ public class TerrainPatch extends Geometry {
|
|
TB.setUpdateNeeded();
|
|
TB.setUpdateNeeded();
|
|
BB.setUpdateNeeded();
|
|
BB.setUpdateNeeded();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Matches the normals along the edge of the patch with the neighbours.
|
|
* Matches the normals along the edge of the patch with the neighbours.
|
|
* Computes the normals for the right, bottom, left, and top edges of the
|
|
* Computes the normals for the right, bottom, left, and top edges of the
|
|
@@ -364,7 +365,7 @@ public class TerrainPatch extends Geometry {
|
|
* *---x---*
|
|
* *---x---*
|
|
* |
|
|
* |
|
|
* *
|
|
* *
|
|
- * It works across the right side of the patch, from the top down to
|
|
|
|
|
|
+ * It works across the right side of the patch, from the top down to
|
|
* the bottom. Then it works on the bottom side of the patch, from the
|
|
* the bottom. Then it works on the bottom side of the patch, from the
|
|
* left to the right.
|
|
* left to the right.
|
|
*/
|
|
*/
|
|
@@ -388,9 +389,9 @@ public class TerrainPatch extends Geometry {
|
|
Vector3f binormal = new Vector3f();
|
|
Vector3f binormal = new Vector3f();
|
|
Vector3f normal = new Vector3f();
|
|
Vector3f normal = new Vector3f();
|
|
|
|
|
|
-
|
|
|
|
|
|
+
|
|
int s = this.getSize()-1;
|
|
int s = this.getSize()-1;
|
|
-
|
|
|
|
|
|
+
|
|
if (right != null) { // right side, works its way down
|
|
if (right != null) { // right side, works its way down
|
|
for (int i=0; i<s+1; i++) {
|
|
for (int i=0; i<s+1; i++) {
|
|
rootPoint.set(0, this.getHeightmapHeight(s,i), 0);
|
|
rootPoint.set(0, this.getHeightmapHeight(s,i), 0);
|
|
@@ -399,26 +400,26 @@ public class TerrainPatch extends Geometry {
|
|
|
|
|
|
if (i == 0) { // top point
|
|
if (i == 0) { // top point
|
|
bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(s,i+1), 1);
|
|
-
|
|
|
|
|
|
+
|
|
if (top == null) {
|
|
if (top == null) {
|
|
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
|
|
} else {
|
|
} else {
|
|
topPoint.set(0, top.getHeightmapHeight(s,s-1), -1);
|
|
topPoint.set(0, top.getHeightmapHeight(s,s-1), -1);
|
|
-
|
|
|
|
|
|
+
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
-
|
|
|
|
|
|
+
|
|
if (topRight != null) {
|
|
if (topRight != null) {
|
|
// setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
// setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (i == s) { // bottom point
|
|
} else if (i == s) { // bottom point
|
|
topPoint.set(0, this.getHeightmapHeight(s,s-1), -1);
|
|
topPoint.set(0, this.getHeightmapHeight(s,s-1), -1);
|
|
-
|
|
|
|
|
|
+
|
|
if (bottom == null) {
|
|
if (bottom == null) {
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
@@ -429,7 +430,7 @@ public class TerrainPatch extends Geometry {
|
|
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
setInBuffer(bottom.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(bottom.getMesh(), s, normal, tangent, binormal);
|
|
-
|
|
|
|
|
|
+
|
|
if (bottomRight != null) {
|
|
if (bottomRight != null) {
|
|
// setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal);
|
|
// setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal);
|
|
}
|
|
}
|
|
@@ -449,41 +450,41 @@ public class TerrainPatch extends Geometry {
|
|
rootPoint.set(0, this.getHeightmapHeight(0,i), 0);
|
|
rootPoint.set(0, this.getHeightmapHeight(0,i), 0);
|
|
leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0);
|
|
leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(1,i), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(1,i), 0);
|
|
-
|
|
|
|
|
|
+
|
|
if (i == 0) { // top point
|
|
if (i == 0) { // top point
|
|
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
|
|
-
|
|
|
|
|
|
+
|
|
if (top == null) {
|
|
if (top == null) {
|
|
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
|
|
} else {
|
|
} else {
|
|
topPoint.set(0, top.getHeightmapHeight(0,s-1), -1);
|
|
topPoint.set(0, top.getHeightmapHeight(0,s-1), -1);
|
|
-
|
|
|
|
|
|
+
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
|
|
setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal);
|
|
-
|
|
|
|
|
|
+
|
|
if (topLeft != null) {
|
|
if (topLeft != null) {
|
|
// setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
// setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (i == s) { // bottom point
|
|
} else if (i == s) { // bottom point
|
|
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
|
|
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
|
|
-
|
|
|
|
|
|
+
|
|
if (bottom == null) {
|
|
if (bottom == null) {
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
} else {
|
|
} else {
|
|
bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1);
|
|
bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1);
|
|
-
|
|
|
|
|
|
+
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(s), normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
|
|
setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal);
|
|
setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal);
|
|
-
|
|
|
|
|
|
+
|
|
if (bottomLeft != null) {
|
|
if (bottomLeft != null) {
|
|
// setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal);
|
|
// setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal);
|
|
}
|
|
}
|
|
@@ -491,7 +492,7 @@ public class TerrainPatch extends Geometry {
|
|
} else { // all in the middle
|
|
} else { // all in the middle
|
|
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
|
|
topPoint.set(0, this.getHeightmapHeight(0,i-1), -1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(0,i+1), 1);
|
|
-
|
|
|
|
|
|
+
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(i), normal, tangent, binormal);
|
|
setInBuffer(this.getMesh(), (s+1)*(i), normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
|
|
setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
|
|
@@ -504,14 +505,14 @@ public class TerrainPatch extends Geometry {
|
|
rootPoint.set(0, this.getHeightmapHeight(i,0), 0);
|
|
rootPoint.set(0, this.getHeightmapHeight(i,0), 0);
|
|
topPoint.set(0, top.getHeightmapHeight(i,s-1), -1);
|
|
topPoint.set(0, top.getHeightmapHeight(i,s-1), -1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(i,1), 1);
|
|
bottomPoint.set(0, this.getHeightmapHeight(i,1), 1);
|
|
-
|
|
|
|
|
|
+
|
|
if (i == 0) { // left corner
|
|
if (i == 0) { // left corner
|
|
// handled by left side pass
|
|
// handled by left side pass
|
|
-
|
|
|
|
|
|
+
|
|
} else if (i == s) { // right corner
|
|
} else if (i == s) { // right corner
|
|
-
|
|
|
|
|
|
+
|
|
// handled by this patch when it does its right side
|
|
// handled by this patch when it does its right side
|
|
-
|
|
|
|
|
|
+
|
|
} else { // all in the middle
|
|
} else { // all in the middle
|
|
leftPoint.set(-1, this.getHeightmapHeight(i-1,0), 0);
|
|
leftPoint.set(-1, this.getHeightmapHeight(i-1,0), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(i+1,0), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(i+1,0), 0);
|
|
@@ -520,9 +521,9 @@ public class TerrainPatch extends Geometry {
|
|
setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
|
|
setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
if (bottom != null) { // bottom side, works its way right
|
|
if (bottom != null) { // bottom side, works its way right
|
|
for (int i=0; i<s+1; i++) {
|
|
for (int i=0; i<s+1; i++) {
|
|
rootPoint.set(0, this.getHeightmapHeight(i,s), 0);
|
|
rootPoint.set(0, this.getHeightmapHeight(i,s), 0);
|
|
@@ -531,11 +532,11 @@ public class TerrainPatch extends Geometry {
|
|
|
|
|
|
if (i == 0) { // left
|
|
if (i == 0) { // left
|
|
// handled by the left side pass
|
|
// handled by the left side pass
|
|
-
|
|
|
|
|
|
+
|
|
} else if (i == s) { // right
|
|
} else if (i == s) { // right
|
|
-
|
|
|
|
|
|
+
|
|
// handled by the right side pass
|
|
// handled by the right side pass
|
|
-
|
|
|
|
|
|
+
|
|
} else { // all in the middle
|
|
} else { // all in the middle
|
|
leftPoint.set(-1, this.getHeightmapHeight(i-1,s), 0);
|
|
leftPoint.set(-1, this.getHeightmapHeight(i-1,s), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(i+1,s), 0);
|
|
rightPoint.set(1, this.getHeightmapHeight(i+1,s), 0);
|
|
@@ -544,22 +545,22 @@ public class TerrainPatch extends Geometry {
|
|
setInBuffer(bottom.getMesh(), i, normal, tangent, binormal);
|
|
setInBuffer(bottom.getMesh(), i, normal, tangent, binormal);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
protected void averageNormalsTangents(
|
|
protected void averageNormalsTangents(
|
|
Vector3f topPoint,
|
|
Vector3f topPoint,
|
|
Vector3f rootPoint,
|
|
Vector3f rootPoint,
|
|
- Vector3f leftPoint,
|
|
|
|
- Vector3f bottomPoint,
|
|
|
|
|
|
+ Vector3f leftPoint,
|
|
|
|
+ Vector3f bottomPoint,
|
|
Vector3f rightPoint,
|
|
Vector3f rightPoint,
|
|
Vector3f normal,
|
|
Vector3f normal,
|
|
Vector3f tangent,
|
|
Vector3f tangent,
|
|
Vector3f binormal)
|
|
Vector3f binormal)
|
|
{
|
|
{
|
|
Vector3f scale = getWorldScale();
|
|
Vector3f scale = getWorldScale();
|
|
-
|
|
|
|
|
|
+
|
|
Vector3f n1 = new Vector3f(0,0,0);
|
|
Vector3f n1 = new Vector3f(0,0,0);
|
|
if (topPoint != null && leftPoint != null) {
|
|
if (topPoint != null && leftPoint != null) {
|
|
n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale)));
|
|
n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale)));
|
|
@@ -576,12 +577,12 @@ public class TerrainPatch extends Geometry {
|
|
if (rightPoint != null && topPoint != null) {
|
|
if (rightPoint != null && topPoint != null) {
|
|
n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale)));
|
|
n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale)));
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
//if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null)
|
|
//if (bottomPoint != null && rightPoint != null && rootTex != null && rightTex != null && bottomTex != null)
|
|
// LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal);
|
|
// LODGeomap.calculateTangent(new Vector3f[]{rootPoint.mult(scale),rightPoint.mult(scale),bottomPoint.mult(scale)}, new Vector2f[]{rootTex,rightTex,bottomTex}, tangent, binormal);
|
|
|
|
|
|
normal.set(n1.add(n2).add(n3).add(n4).normalize());
|
|
normal.set(n1.add(n2).add(n3).add(n4).normalize());
|
|
-
|
|
|
|
|
|
+
|
|
tangent.set(normal.cross(new Vector3f(0,0,1)).normalize());
|
|
tangent.set(normal.cross(new Vector3f(0,0,1)).normalize());
|
|
binormal.set(new Vector3f(1,0,0).cross(normal).normalize());
|
|
binormal.set(new Vector3f(1,0,0).cross(normal).normalize());
|
|
}
|
|
}
|
|
@@ -592,11 +593,11 @@ public class TerrainPatch extends Geometry {
|
|
.crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
|
|
.crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
|
|
return normal;
|
|
return normal;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
protected Vector3f getMeshNormal(int x, int z) {
|
|
protected Vector3f getMeshNormal(int x, int z) {
|
|
if (x >= size || z >= size)
|
|
if (x >= size || z >= size)
|
|
return null; // out of range
|
|
return null; // out of range
|
|
-
|
|
|
|
|
|
+
|
|
int index = (z*size+x)*3;
|
|
int index = (z*size+x)*3;
|
|
FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData();
|
|
FloatBuffer nb = (FloatBuffer)this.getMesh().getBuffer(Type.Normal).getData();
|
|
Vector3f normal = new Vector3f();
|
|
Vector3f normal = new Vector3f();
|
|
@@ -609,7 +610,7 @@ public class TerrainPatch extends Geometry {
|
|
protected float getHeight(int x, int z, float xm, float zm) {
|
|
protected float getHeight(int x, int z, float xm, float zm) {
|
|
return geomap.getHeight(x,z,xm,zm);
|
|
return geomap.getHeight(x,z,xm,zm);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Locks the mesh (sets it static) to improve performance.
|
|
* Locks the mesh (sets it static) to improve performance.
|
|
* But it it not editable then. Set unlock to make it editable.
|
|
* But it it not editable then. Set unlock to make it editable.
|
|
@@ -626,7 +627,7 @@ public class TerrainPatch extends Geometry {
|
|
public void unlockMesh() {
|
|
public void unlockMesh() {
|
|
getMesh().setDynamic();
|
|
getMesh().setDynamic();
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* Returns the offset amount this terrain patch uses for textures.
|
|
* Returns the offset amount this terrain patch uses for textures.
|
|
*
|
|
*
|
|
@@ -797,7 +798,7 @@ public class TerrainPatch extends Geometry {
|
|
protected void setLodBottom(int lodBottom) {
|
|
protected void setLodBottom(int lodBottom) {
|
|
this.lodBottom = lodBottom;
|
|
this.lodBottom = lodBottom;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
/*public void setLodCalculator(LodCalculatorFactory lodCalculatorFactory) {
|
|
/*public void setLodCalculator(LodCalculatorFactory lodCalculatorFactory) {
|
|
this.lodCalculatorFactory = lodCalculatorFactory;
|
|
this.lodCalculatorFactory = lodCalculatorFactory;
|
|
setLodCalculator(lodCalculatorFactory.createCalculator(this));
|
|
setLodCalculator(lodCalculatorFactory.createCalculator(this));
|
|
@@ -812,7 +813,7 @@ public class TerrainPatch extends Geometry {
|
|
if (other instanceof BoundingVolume)
|
|
if (other instanceof BoundingVolume)
|
|
if (!getWorldBound().intersects((BoundingVolume)other))
|
|
if (!getWorldBound().intersects((BoundingVolume)other))
|
|
return 0;
|
|
return 0;
|
|
-
|
|
|
|
|
|
+
|
|
if(other instanceof Ray)
|
|
if(other instanceof Ray)
|
|
return collideWithRay((Ray)other, results);
|
|
return collideWithRay((Ray)other, results);
|
|
else if (other instanceof BoundingVolume)
|
|
else if (other instanceof BoundingVolume)
|
|
@@ -853,7 +854,7 @@ public class TerrainPatch extends Geometry {
|
|
* This most definitely is not optimized.
|
|
* This most definitely is not optimized.
|
|
*/
|
|
*/
|
|
private int collideWithBoundingBox(BoundingBox bbox, CollisionResults results) {
|
|
private int collideWithBoundingBox(BoundingBox bbox, CollisionResults results) {
|
|
-
|
|
|
|
|
|
+
|
|
// test the four corners, for cases where the bbox dimensions are less than the terrain grid size, which is probably most of the time
|
|
// test the four corners, for cases where the bbox dimensions are less than the terrain grid size, which is probably most of the time
|
|
Vector3f topLeft = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x-bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
|
|
Vector3f topLeft = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x-bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
|
|
Vector3f topRight = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x+bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
|
|
Vector3f topRight = worldCoordinateToLocal(new Vector3f(bbox.getCenter().x+bbox.getXExtent(), 0, bbox.getCenter().z-bbox.getZExtent()));
|
|
@@ -872,11 +873,11 @@ public class TerrainPatch extends Geometry {
|
|
t = getTriangle(bottomRight.x, bottomRight.z);
|
|
t = getTriangle(bottomRight.x, bottomRight.z);
|
|
if (t != null && bbox.collideWith(t, results) > 0)
|
|
if (t != null && bbox.collideWith(t, results) > 0)
|
|
return 1;
|
|
return 1;
|
|
-
|
|
|
|
|
|
+
|
|
// box is larger than the points on the terrain, so test against the points
|
|
// box is larger than the points on the terrain, so test against the points
|
|
for (float z=topLeft.z; z<bottomLeft.z; z+=1) {
|
|
for (float z=topLeft.z; z<bottomLeft.z; z+=1) {
|
|
for (float x=topLeft.x; x<topRight.x; x+=1) {
|
|
for (float x=topLeft.x; x<topRight.x; x+=1) {
|
|
-
|
|
|
|
|
|
+
|
|
if (x < 0 || z < 0 || x >= size || z >= size)
|
|
if (x < 0 || z < 0 || x >= size || z >= size)
|
|
continue;
|
|
continue;
|
|
t = getTriangle(x,z);
|
|
t = getTriangle(x,z);
|
|
@@ -895,7 +896,7 @@ public class TerrainPatch extends Geometry {
|
|
// this reduces the save size to 10% by not saving the mesh
|
|
// this reduces the save size to 10% by not saving the mesh
|
|
Mesh temp = getMesh();
|
|
Mesh temp = getMesh();
|
|
mesh = null;
|
|
mesh = null;
|
|
-
|
|
|
|
|
|
+
|
|
super.write(ex);
|
|
super.write(ex);
|
|
OutputCapsule oc = ex.getCapsule(this);
|
|
OutputCapsule oc = ex.getCapsule(this);
|
|
oc.write(size, "size", 16);
|
|
oc.write(size, "size", 16);
|
|
@@ -908,7 +909,7 @@ public class TerrainPatch extends Geometry {
|
|
//oc.write(lodCalculatorFactory, "lodCalculatorFactory", null);
|
|
//oc.write(lodCalculatorFactory, "lodCalculatorFactory", null);
|
|
oc.write(lodEntropy, "lodEntropy", null);
|
|
oc.write(lodEntropy, "lodEntropy", null);
|
|
oc.write(geomap, "geomap", null);
|
|
oc.write(geomap, "geomap", null);
|
|
-
|
|
|
|
|
|
+
|
|
setMesh(temp);
|
|
setMesh(temp);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -927,7 +928,7 @@ public class TerrainPatch extends Geometry {
|
|
//lodCalculatorFactory = (LodCalculatorFactory) ic.readSavable("lodCalculatorFactory", null);
|
|
//lodCalculatorFactory = (LodCalculatorFactory) ic.readSavable("lodCalculatorFactory", null);
|
|
lodEntropy = ic.readFloatArray("lodEntropy", null);
|
|
lodEntropy = ic.readFloatArray("lodEntropy", null);
|
|
geomap = (LODGeomap) ic.readSavable("geomap", null);
|
|
geomap = (LODGeomap) ic.readSavable("geomap", null);
|
|
-
|
|
|
|
|
|
+
|
|
Mesh regen = geomap.createMesh(stepScale, new Vector2f(1,1), offset, offsetAmount, totalSize, false);
|
|
Mesh regen = geomap.createMesh(stepScale, new Vector2f(1,1), offset, offsetAmount, totalSize, false);
|
|
setMesh(regen);
|
|
setMesh(regen);
|
|
//TangentBinormalGenerator.generate(this); // note that this will be removed
|
|
//TangentBinormalGenerator.generate(this); // note that this will be removed
|
|
@@ -955,6 +956,33 @@ public class TerrainPatch extends Geometry {
|
|
return clone;
|
|
return clone;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
+ * Called internally by com.jme3.util.clone.Cloner. Do not call directly.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public void cloneFields( Cloner cloner, Object original ) {
|
|
|
|
+
|
|
|
|
+ this.stepScale = cloner.clone(stepScale);
|
|
|
|
+ this.offset = cloner.clone(offset);
|
|
|
|
+
|
|
|
|
+ this.leftNeighbour = null;
|
|
|
|
+ this.topNeighbour = null;
|
|
|
|
+ this.rightNeighbour = null;
|
|
|
|
+ this.bottomNeighbour = null;
|
|
|
|
+
|
|
|
|
+ // Don't feel like making geomap cloneable tonight
|
|
|
|
+ // so I'll copy the old logic.
|
|
|
|
+ this.geomap = new LODGeomap(size, geomap.getHeightArray());
|
|
|
|
+ Mesh m = geomap.createMesh(stepScale, Vector2f.UNIT_XY, offset, offsetAmount, totalSize, false);
|
|
|
|
+ this.setMesh(m);
|
|
|
|
+
|
|
|
|
+ // In this case, we always clone material even if the cloner is setup
|
|
|
|
+ // not to clone it. Terrain uses mutable textures and stuff so it's important
|
|
|
|
+ // to clone it. (At least that's my understanding and is evidenced by the old
|
|
|
|
+ // clone code specifically cloning material.) -pspeed
|
|
|
|
+ this.material = material.clone();
|
|
|
|
+ }
|
|
|
|
+
|
|
protected void ensurePositiveVolumeBBox() {
|
|
protected void ensurePositiveVolumeBBox() {
|
|
if (getModelBound() instanceof BoundingBox) {
|
|
if (getModelBound() instanceof BoundingBox) {
|
|
if (((BoundingBox)getModelBound()).getYExtent() < 0.001f) {
|
|
if (((BoundingBox)getModelBound()).getYExtent() < 0.001f) {
|