JmeCloneable related changes to TerrainQuad and TerrainPatch. Fixed
something I missed in NormalRecalcControl.
This commit is contained in:
parent
eda92656dd
commit
7b29c58fe0
@ -69,12 +69,23 @@ public class NormalRecalcControl extends AbstractControl {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
public Object jmeClone() {
|
public Object jmeClone() {
|
||||||
NormalRecalcControl control = (NormalRecalcControl)super.jmeClone();
|
NormalRecalcControl control = (NormalRecalcControl)super.jmeClone();
|
||||||
control.setEnabled(true);
|
control.setEnabled(true);
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called internally by com.jme3.util.clone.Cloner. Do not call directly.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void cloneFields( Cloner cloner, Object original ) {
|
||||||
|
this.terrain = cloner.clone(terrain);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Control cloneForSpatial(Spatial spatial) {
|
public Control cloneForSpatial(Spatial spatial) {
|
||||||
@ -83,7 +94,7 @@ public class NormalRecalcControl extends AbstractControl {
|
|||||||
control.setEnabled(true);
|
control.setEnabled(true);
|
||||||
return control;
|
return control;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setSpatial(Spatial spatial) {
|
public void setSpatial(Spatial spatial) {
|
||||||
super.setSpatial(spatial);
|
super.setSpatial(spatial);
|
||||||
|
@ -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
|
* 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,
|
* 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 leftPoint,
|
||||||
Vector3f bottomPoint,
|
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) {
|
||||||
|
@ -55,6 +55,7 @@ import com.jme3.terrain.geomipmap.picking.BresenhamTerrainPicker;
|
|||||||
import com.jme3.terrain.geomipmap.picking.TerrainPickData;
|
import com.jme3.terrain.geomipmap.picking.TerrainPickData;
|
||||||
import com.jme3.terrain.geomipmap.picking.TerrainPicker;
|
import com.jme3.terrain.geomipmap.picking.TerrainPicker;
|
||||||
import com.jme3.util.TangentBinormalGenerator;
|
import com.jme3.util.TangentBinormalGenerator;
|
||||||
|
import com.jme3.util.clone.Cloner;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -126,7 +127,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
private Vector3f lastScale = Vector3f.UNIT_XYZ;
|
private Vector3f lastScale = Vector3f.UNIT_XYZ;
|
||||||
|
|
||||||
protected NeighbourFinder neighbourFinder;
|
protected NeighbourFinder neighbourFinder;
|
||||||
|
|
||||||
public TerrainQuad() {
|
public TerrainQuad() {
|
||||||
super("Terrain");
|
super("Terrain");
|
||||||
}
|
}
|
||||||
@ -144,24 +145,24 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
* </p>
|
* </p>
|
||||||
* @param name the name of the scene element. This is required for
|
* @param name the name of the scene element. This is required for
|
||||||
* identification and comparison purposes.
|
* identification and comparison purposes.
|
||||||
* @param patchSize size of the individual patches (geometry). Power of 2 plus 1,
|
* @param patchSize size of the individual patches (geometry). Power of 2 plus 1,
|
||||||
* must be smaller than totalSize. (eg. 33, 65...)
|
* must be smaller than totalSize. (eg. 33, 65...)
|
||||||
* @param totalSize the size of this entire terrain (on one side). Power of 2 plus 1
|
* @param totalSize the size of this entire terrain (on one side). Power of 2 plus 1
|
||||||
* (eg. 513, 1025, 2049...)
|
* (eg. 513, 1025, 2049...)
|
||||||
* @param heightMap The height map to generate the terrain from (a flat
|
* @param heightMap The height map to generate the terrain from (a flat
|
||||||
* height map will be generated if this is null). The size of one side of the heightmap
|
* height map will be generated if this is null). The size of one side of the heightmap
|
||||||
* must match the totalSize. So a 513x513 heightmap is needed for a terrain with totalSize of 513.
|
* must match the totalSize. So a 513x513 heightmap is needed for a terrain with totalSize of 513.
|
||||||
*/
|
*/
|
||||||
public TerrainQuad(String name, int patchSize, int totalSize, float[] heightMap) {
|
public TerrainQuad(String name, int patchSize, int totalSize, float[] heightMap) {
|
||||||
this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMap);
|
this(name, patchSize, totalSize, Vector3f.UNIT_XYZ, heightMap);
|
||||||
|
|
||||||
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size*2, Float.MAX_VALUE, size*2);
|
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), size*2, Float.MAX_VALUE, size*2);
|
||||||
fixNormalEdges(affectedAreaBBox);
|
fixNormalEdges(affectedAreaBBox);
|
||||||
addControl(new NormalRecalcControl(this));
|
addControl(new NormalRecalcControl(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name the name of the scene element. This is required for
|
* @param name the name of the scene element. This is required for
|
||||||
* identification and comparison purposes.
|
* identification and comparison purposes.
|
||||||
* @param patchSize size of the individual patches
|
* @param patchSize size of the individual patches
|
||||||
@ -176,7 +177,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name the name of the scene element. This is required for
|
* @param name the name of the scene element. This is required for
|
||||||
* identification and comparison purposes.
|
* identification and comparison purposes.
|
||||||
* @param patchSize size of the individual patches
|
* @param patchSize size of the individual patches
|
||||||
@ -192,9 +193,9 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
//fixNormalEdges(affectedAreaBBox);
|
//fixNormalEdges(affectedAreaBBox);
|
||||||
//addControl(new NormalRecalcControl(this));
|
//addControl(new NormalRecalcControl(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param name the name of the scene element. This is required for
|
* @param name the name of the scene element. This is required for
|
||||||
* identification and comparison purposes.
|
* identification and comparison purposes.
|
||||||
* @param patchSize size of the individual patches
|
* @param patchSize size of the individual patches
|
||||||
@ -217,17 +218,17 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
Vector2f offset, float offsetAmount)
|
Vector2f offset, float offsetAmount)
|
||||||
{
|
{
|
||||||
super(name);
|
super(name);
|
||||||
|
|
||||||
if (heightMap == null)
|
if (heightMap == null)
|
||||||
heightMap = generateDefaultHeightMap(quadSize);
|
heightMap = generateDefaultHeightMap(quadSize);
|
||||||
|
|
||||||
if (!FastMath.isPowerOfTwo(quadSize - 1)) {
|
if (!FastMath.isPowerOfTwo(quadSize - 1)) {
|
||||||
throw new RuntimeException("size given: " + quadSize + " Terrain quad sizes may only be (2^N + 1)");
|
throw new RuntimeException("size given: " + quadSize + " Terrain quad sizes may only be (2^N + 1)");
|
||||||
}
|
}
|
||||||
if (FastMath.sqrt(heightMap.length) > quadSize) {
|
if (FastMath.sqrt(heightMap.length) > quadSize) {
|
||||||
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Heightmap size is larger than the terrain size. Make sure your heightmap image is the same size as the terrain!");
|
Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Heightmap size is larger than the terrain size. Make sure your heightmap image is the same size as the terrain!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
this.offsetAmount = offsetAmount;
|
this.offsetAmount = offsetAmount;
|
||||||
this.totalSize = totalSize;
|
this.totalSize = totalSize;
|
||||||
@ -248,7 +249,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
public void recalculateAllNormals() {
|
public void recalculateAllNormals() {
|
||||||
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), totalSize*2, Float.MAX_VALUE, totalSize*2);
|
affectedAreaBBox = new BoundingBox(new Vector3f(0,0,0), totalSize*2, Float.MAX_VALUE, totalSize*2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create just a flat heightmap
|
* Create just a flat heightmap
|
||||||
*/
|
*/
|
||||||
@ -267,11 +268,11 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
//TODO background-thread this if it ends up being expensive
|
//TODO background-thread this if it ends up being expensive
|
||||||
fixNormals(affectedAreaBBox); // the affected patches
|
fixNormals(affectedAreaBBox); // the affected patches
|
||||||
fixNormalEdges(affectedAreaBBox); // the edges between the patches
|
fixNormalEdges(affectedAreaBBox); // the edges between the patches
|
||||||
|
|
||||||
setNormalRecalcNeeded(null); // set to false
|
setNormalRecalcNeeded(null); // set to false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches the transforms (except rotation) so the LOD calculator,
|
* Caches the transforms (except rotation) so the LOD calculator,
|
||||||
* which runs on a separate thread, can access them safely.
|
* which runs on a separate thread, can access them safely.
|
||||||
@ -343,7 +344,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
public Material getMaterial() {
|
public Material getMaterial() {
|
||||||
return getMaterial(null);
|
return getMaterial(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Material getMaterial(Vector3f worldLocation) {
|
public Material getMaterial(Vector3f worldLocation) {
|
||||||
// get the material from one of the children. They all share the same material
|
// get the material from one of the children. They all share the same material
|
||||||
if (children != null) {
|
if (children != null) {
|
||||||
@ -362,7 +363,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
public int getNumMajorSubdivisions() {
|
public int getNumMajorSubdivisions() {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected boolean calculateLod(List<Vector3f> location, HashMap<String,UpdatedTerrainPatch> updates, LodCalculator lodCalculator) {
|
protected boolean calculateLod(List<Vector3f> location, HashMap<String,UpdatedTerrainPatch> updates, LodCalculator lodCalculator) {
|
||||||
|
|
||||||
@ -434,7 +435,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
utp.setBottomLod(utpD.getNewLod());
|
utp.setBottomLod(utpD.getNewLod());
|
||||||
utpD.setTopLod(utp.getNewLod());
|
utpD.setTopLod(utp.getNewLod());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (left != null) {
|
if (left != null) {
|
||||||
UpdatedTerrainPatch utpL = updated.get(left.getName());
|
UpdatedTerrainPatch utpL = updated.get(left.getName());
|
||||||
if (utpL == null) {
|
if (utpL == null) {
|
||||||
@ -478,7 +479,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find any neighbours that should have their edges seamed because another neighbour
|
* Find any neighbours that should have their edges seamed because another neighbour
|
||||||
* changed its LOD to a greater value (less detailed)
|
* changed its LOD to a greater value (less detailed)
|
||||||
@ -587,10 +588,10 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Quadrants, world coordinates, and heightmap coordinates (Y-up):
|
* Quadrants, world coordinates, and heightmap coordinates (Y-up):
|
||||||
*
|
*
|
||||||
* -z
|
* -z
|
||||||
* -u |
|
* -u |
|
||||||
* -v 1|3
|
* -v 1|3
|
||||||
* -x ----+---- x
|
* -x ----+---- x
|
||||||
* 2|4 u
|
* 2|4 u
|
||||||
* | v
|
* | v
|
||||||
@ -668,7 +669,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
quad3.setLocalTranslation(origin3);
|
quad3.setLocalTranslation(origin3);
|
||||||
quad3.quadrant = 3;
|
quad3.quadrant = 3;
|
||||||
this.attachChild(quad3);
|
this.attachChild(quad3);
|
||||||
|
|
||||||
// 4 lower right of heightmap, lower right quad
|
// 4 lower right of heightmap, lower right quad
|
||||||
float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
|
float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
|
||||||
split - 1, split);
|
split - 1, split);
|
||||||
@ -892,7 +893,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will cause all normals for this terrain quad to be recalculated
|
* This will cause all normals for this terrain quad to be recalculated
|
||||||
*/
|
*/
|
||||||
@ -1024,14 +1025,14 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
int col;
|
int col;
|
||||||
int row;
|
int row;
|
||||||
Spatial child;
|
Spatial child;
|
||||||
|
|
||||||
QuadrantChild(int col, int row, Spatial child) {
|
QuadrantChild(int col, int row, Spatial child) {
|
||||||
this.col = col;
|
this.col = col;
|
||||||
this.row = row;
|
this.row = row;
|
||||||
this.child = child;
|
this.child = child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private QuadrantChild findMatchingChild(int x, int z) {
|
private QuadrantChild findMatchingChild(int x, int z) {
|
||||||
int quad = findQuadrant(x, z);
|
int quad = findQuadrant(x, z);
|
||||||
int split = (size + 1) >> 1;
|
int split = (size + 1) >> 1;
|
||||||
@ -1069,7 +1070,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the interpolated height of the terrain at the specified point.
|
* Get the interpolated height of the terrain at the specified point.
|
||||||
* @param xz the location to get the height for
|
* @param xz the location to get the height for
|
||||||
@ -1090,7 +1091,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
* gets an interpolated value at the specified point
|
* gets an interpolated value at the specified point
|
||||||
*/
|
*/
|
||||||
protected float getHeight(int x, int z, float xm, float zm) {
|
protected float getHeight(int x, int z, float xm, float zm) {
|
||||||
|
|
||||||
QuadrantChild match = findMatchingChild(x,z);
|
QuadrantChild match = findMatchingChild(x,z);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
if (match.child instanceof TerrainQuad) {
|
if (match.child instanceof TerrainQuad) {
|
||||||
@ -1107,10 +1108,10 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)(totalSize-1) / 2f);
|
float x = (float)(((xz.x - getWorldTranslation().x) / getWorldScale().x) + (float)(totalSize-1) / 2f);
|
||||||
float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)(totalSize-1) / 2f);
|
float z = (float)(((xz.y - getWorldTranslation().z) / getWorldScale().z) + (float)(totalSize-1) / 2f);
|
||||||
Vector3f normal = getNormal(x, z, xz);
|
Vector3f normal = getNormal(x, z, xz);
|
||||||
|
|
||||||
return normal;
|
return normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Vector3f getNormal(float x, float z, Vector2f xz) {
|
protected Vector3f getNormal(float x, float z, Vector2f xz) {
|
||||||
x-=0.5f;
|
x-=0.5f;
|
||||||
z-=0.5f;
|
z-=0.5f;
|
||||||
@ -1125,15 +1126,15 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
// v3--v4 | Z
|
// v3--v4 | Z
|
||||||
// |
|
// |
|
||||||
// <-------Y
|
// <-------Y
|
||||||
// X
|
// X
|
||||||
Vector3f n1 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.ceil(z));
|
Vector3f n1 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.ceil(z));
|
||||||
Vector3f n2 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.ceil(z));
|
Vector3f n2 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.ceil(z));
|
||||||
Vector3f n3 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.floor(z));
|
Vector3f n3 = getMeshNormal((int) FastMath.ceil(x), (int) FastMath.floor(z));
|
||||||
Vector3f n4 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.floor(z));
|
Vector3f n4 = getMeshNormal((int) FastMath.floor(x), (int) FastMath.floor(z));
|
||||||
|
|
||||||
return n1.add(n2).add(n3).add(n4).normalize();
|
return n1.add(n2).add(n3).add(n4).normalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setHeight(Vector2f xz, float height) {
|
public void setHeight(Vector2f xz, float height) {
|
||||||
List<Vector2f> coord = new ArrayList<Vector2f>();
|
List<Vector2f> coord = new ArrayList<Vector2f>();
|
||||||
coord.add(xz);
|
coord.add(xz);
|
||||||
@ -1291,7 +1292,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
|
return (x >= 0 && x <= totalSize && z >= 0 && z <= totalSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public int getTerrainSize() {
|
public int getTerrainSize() {
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
@ -1750,7 +1751,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
totalSize = c.readInt("totalSize", 0);
|
totalSize = c.readInt("totalSize", 0);
|
||||||
//lodCalculator = (LodCalculator) c.readSavable("lodCalculator", createDefaultLodCalculator());
|
//lodCalculator = (LodCalculator) c.readSavable("lodCalculator", createDefaultLodCalculator());
|
||||||
//lodCalculatorFactory = (LodCalculatorFactory) c.readSavable("lodCalculatorFactory", null);
|
//lodCalculatorFactory = (LodCalculatorFactory) c.readSavable("lodCalculatorFactory", null);
|
||||||
|
|
||||||
if ( !(getParent() instanceof TerrainQuad) ) {
|
if ( !(getParent() instanceof TerrainQuad) ) {
|
||||||
BoundingBox all = new BoundingBox(getWorldTranslation(), totalSize, totalSize, totalSize);
|
BoundingBox all = new BoundingBox(getWorldTranslation(), totalSize, totalSize, totalSize);
|
||||||
affectedAreaBBox = all;
|
affectedAreaBBox = all;
|
||||||
@ -1793,10 +1794,10 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
quadClone.quadrant = quadrant;
|
quadClone.quadrant = quadrant;
|
||||||
//quadClone.lodCalculatorFactory = lodCalculatorFactory.clone();
|
//quadClone.lodCalculatorFactory = lodCalculatorFactory.clone();
|
||||||
//quadClone.lodCalculator = lodCalculator.clone();
|
//quadClone.lodCalculator = lodCalculator.clone();
|
||||||
|
|
||||||
TerrainLodControl lodControlCloned = this.getControl(TerrainLodControl.class);
|
TerrainLodControl lodControlCloned = this.getControl(TerrainLodControl.class);
|
||||||
TerrainLodControl lodControl = quadClone.getControl(TerrainLodControl.class);
|
TerrainLodControl lodControl = quadClone.getControl(TerrainLodControl.class);
|
||||||
|
|
||||||
if (lodControlCloned != null && !(getParent() instanceof TerrainQuad)) {
|
if (lodControlCloned != null && !(getParent() instanceof TerrainQuad)) {
|
||||||
//lodControlCloned.setLodCalculator(lodControl.getLodCalculator().clone());
|
//lodControlCloned.setLodCalculator(lodControl.getLodCalculator().clone());
|
||||||
}
|
}
|
||||||
@ -1806,7 +1807,25 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
|
|
||||||
return quadClone;
|
return quadClone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 was not cloned before... I think that's a mistake.
|
||||||
|
this.affectedAreaBBox = cloner.clone(affectedAreaBBox);
|
||||||
|
|
||||||
|
// picker is not cloneable and not cloned. This also seems like
|
||||||
|
// a mistake if you ever load the same terrain twice.
|
||||||
|
// this.picker = cloner.clone(picker);
|
||||||
|
|
||||||
|
// neighbourFinder is also not cloned. Maybe that's ok.
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setParent(Node parent) {
|
protected void setParent(Node parent) {
|
||||||
super.setParent(parent);
|
super.setParent(parent);
|
||||||
@ -1815,7 +1834,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
clearCaches();
|
clearCaches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes any cached references this terrain is holding, in particular
|
* Removes any cached references this terrain is holding, in particular
|
||||||
* the TerrainPatch's neighbour references.
|
* the TerrainPatch's neighbour references.
|
||||||
@ -1834,7 +1853,7 @@ public class TerrainQuad extends Node implements Terrain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxLod() {
|
public int getMaxLod() {
|
||||||
if (maxLod < 0)
|
if (maxLod < 0)
|
||||||
maxLod = Math.max(1, (int) (FastMath.log(size-1)/FastMath.log(2)) -1); // -1 forces our minimum of 4 triangles wide
|
maxLod = Math.max(1, (int) (FastMath.log(size-1)/FastMath.log(2)) -1); // -1 forces our minimum of 4 triangles wide
|
||||||
|
Loading…
x
Reference in New Issue
Block a user