📄 202f0d37e0c5001d1cd1e38dc83e3a87
字号:
package JavaTerrain;
import java.awt.Image;
import java.awt.image.*;
import java.awt.Component;
import java.util.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import javax.media.j3d.*;
import javax.swing.JButton;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.image.TextureLoader;
public class Terrain extends Shape3D implements GeometryUpdater, MouseBehaviorCallback {
//=== CONSTANTS ===============================================================================================
private static final float MAX_F = Float.MAX_VALUE; // shortcut
private static final int FLOATS_PER_VERTEX = 5; // s,t, x,y,z
private static final int NW = 0, W = 1, SW = 2, S = 3, SE = 4, E = 5, NE = 6, N = 7, C = 8;
private static final int NUL = 0, NLL = 1, NLR = 2, NUR = 3,
FUL = 4, FLL = 5, FLR = 6, FUR = 7;
private static final int LEFT = 0, RIGHT = 1, TOP = 2, BOTTOM = 3, NEAR = 4, FAR = 5;
//=== VARIABLES ===============================================================================================
//--- some Java 3D classes ----------------------------------------------------------------
private SimpleUniverse SimpleU; // ref. to Universe
private Texture2D Texture; // the texture
private TriangleArray TerrainTA; // contains vertices and tex coords
private Geometry TGeometry; // local geometry
private Appearance TAppearance; // local appearance
//--- arrays ------------------------------------------------------------------------------
private float[] Vertices; // positions saved for reference
private float[] TexCoords; // tex coords saved for reference
private float[] Interleaved; // working array, size: max #vertices * 5
private float[] QuadMatrix; // represents quad tree (and contains heights)
private float[] ErrorMatrix; // contains d2 error values
//--- diverse values ----------------------------------------------------------------------
private int MinGlobalRes = 12; // min global res., the higher the more vertices
private float DesiredRes = 22.0f; // desired global resolution
private float D2K; // factor for neighboring D2-values
private float VertexSpacing; // distance between two height values (resolution)
private int Width; // num. of height values in x- and y-direction
private int Level; // max num of levels
private float MaxHeight; // height of 'highest' elevation
private int NumFans; // num of Fans
private int VNum; // num of Vertices
private float HeightAboveGround; // height above ground
//--- for Geometry updates ----------------------------------------------------------------
private Transform3D GUT3D = new Transform3D();
private Vector3f EyePos = new Vector3f();
private boolean CreateNewTA = true; // if array has been resized
private boolean GeoMorph = true; // use geomorphing?
private boolean TextureRamp = false; // real texture or generated ramp?
//--- for view frustum culling ------------------------------------------------------------
private Point3d Point = new Point3d();
private Vector4d[] Planes = new Vector4d[6];
private Vector3d[] Normals = new Vector3d[6];
private Vector3d[] Vectors = new Vector3d[2];
private Point3d[] Points = new Point3d[8];
private BoundingPolytope ViewFrustum = new BoundingPolytope();
private BoundingSphere BoundsSphere = new BoundingSphere();
private JButton Abutton = new JButton();
//=== METHODS =================================================================================================
//=== Constructor ==========================================================================================
public Terrain(SimpleUniverse su, int[] hMap, Texture2D tex2D, float cx, float cz, float vertSpacing,
float maxHeight) {
//--- initialization ----------------------------------------------------------------------
SimpleU = su;
Texture = tex2D;
VertexSpacing = vertSpacing;
MaxHeight = maxHeight;
D2K = (float) MinGlobalRes / (2.0f * (MinGlobalRes - 1.0f));
Width = (int) Math.sqrt((double) hMap.length);
Level = (int) (Math.log ((double) (Width - 1)) / Math.log(2.0d));
NumFans = (int) Math.pow (4.0, (double) (Level - 1));
//--- create Texture2D ? ------------------------------------------------------------------
int h = 256;
if (Texture == null) {
TextureRamp = true;
int[] c = new int[2 * h];
int index = 0;
for (int y = h-1; y >= 0; y--) {
int val = 255 << 24;
int green = ((y * 135) / (h - 1)) + 120;
if (y % 10 == 0) { green -= 20; }
val |= (green << 8);
c[index++] = val;
c[index++] = val;
}
Canvas3D c3d = SimpleU.getViewer().getCanvases();
Image img = c3d.createImage((ImageProducer)
new MemoryImageSource(2, h, c, 0, 2));
TextureLoader texLoader = new TextureLoader(img, c3d);
ImageComponent2D ic2d = texLoader.getImage();
Texture = new Texture2D(Texture.BASE_LEVEL, Texture.RGB,
ic2d.getWidth(), ic2d.getHeight());
Texture.setImage(0, ic2d);
Texture.setEnable(true);
Texture.setMinFilter(Texture.NICEST);
Texture.setMagFilter(Texture.NICEST);
}
//--- allocate memory ---------------------------------------------------------------------
for (int i = 0; i < Planes.length; i++) { Planes [i] = new Vector4d(); }
for (int i = 0; i < Normals.length; i++) { Normals[i] = new Vector3d(); }
for (int i = 0; i < Vectors.length; i++) { Vectors[i] = new Vector3d(); }
for (int i = 0; i < Points.length; i++) { Points [i] = new Point3d(); }
Vertices = new float[Width * Width * 3];
TexCoords = new float[Width * Width * 2];
QuadMatrix = new float[Width * Width ];
ErrorMatrix = new float[Width * Width ];
Interleaved = new float[10002 * FLOATS_PER_VERTEX];
Arrays.fill(QuadMatrix, MAX_F);
//--- fill Vertices and TexCoords arrays with values --------------------------------------
float mid = (float) Width * VertexSpacing / 2.0f;
float step = 1.0f / (float) Width; // Width steps between [0..1.0] for:
float s, t = 1.0f; // tex coords
int vnum = 0; // vertex number
float heightSteps = MaxHeight / 255.0f;
for (int z = 0; z < Width; z++, t-=step) {
s = 0.0f;
for (int x = 0; x < Width; x++, vnum++, s+=step) {
setVertex(Vertices, vnum,(x * VertexSpacing - mid + cx),
((float) hMap[vnum] * heightSteps),
(z * VertexSpacing - mid + cz));
if (TextureRamp) {
setVertex2(TexCoords, vnum,
0.25f, ((float) hMap[vnum] / 255.0f));
}
else {
setVertex2(TexCoords, vnum, s, t);
}
}
}
//--- set Geometry and Appearance ---------------------------------------------------------
setCapability(ALLOW_GEOMETRY_WRITE);
setCapability(ALLOW_APPEARANCE_WRITE);
Abutton.setText("Option");
calcD2ErrorMatrix();
createGeometry();
TAppearance = createAppearance(true);
setAppearance(TAppearance); // setGeometry(TGeometry) exec. in createGeometry
}
//=== Vertex manipulation ==================================================================================
private void setVertex(float[] array, int vnum, float x, float y, float z) {
vnum *= 3; // vertex number * #values per vertex
array[vnum ] = x;
array[vnum+1] = y;
array[vnum+2] = z;
}
private void setVertex2(float[] array, int vnum, float s, float t) {
vnum *= 2; // vertex number * #values per vertex
array[vnum ] = s;
array[vnum+1] = t;
}
private void getVertex(int vnum, Point3d point) {
vnum *= 3;
point.x = Vertices[vnum ];
point.y = Vertices[vnum + 1];
point.z = Vertices[vnum + 2];
}
//=== ErrorMatrix calculations =============================================================================
private void calcD2ErrorMatrix() {
//--- call recursive function for setting initial D2-Values ---
calcD2ErrorMatrixRec(Width / 2, Width / 2, Width, 1);
//--- ensure max level difference of 1 ------------------------
propagateD2Errors();
}
private void calcD2ErrorMatrixRec(int centerX, int centerZ, int width, int level) {
if (level <= Level) {
//--- current value -------------------------------------------------------------
int nodeIndex = centerZ * Width + centerX;
ErrorMatrix[nodeIndex] = calcD2Value(centerX, centerZ, width);
//--- descend tree --------------------------------------------------------------
int w2 = width / 2;
int w4 = width / 4;
calcD2ErrorMatrixRec(centerX - w4, centerZ + w4, w2, level + 1); // nw child
calcD2ErrorMatrixRec(centerX + w4, centerZ + w4, w2, level + 1); // ne child
calcD2ErrorMatrixRec(centerX + w4, centerZ - w4, w2, level + 1); // se child
calcD2ErrorMatrixRec(centerX - w4, centerZ - w4, w2, level + 1); // sw child
}
}
private float calcD2Value(int centerX, int centerZ, int width) {
//--- init needed vars -------------------------------------------------------------
int rx = width / 2; // radius offset in x direction
int rz = rx * Width; // radius offset in z direction
int c = centerZ * Width + centerX; // center vertex
int n = c - rz; // northern vertex
int w = c - rx; // western
int s = c + rz; // southern
int e = c + rx; // eastern
int nw = n - rx; // ...
int sw = s - rx;
int se = s + rx;
int ne = n + rx;
float[] v = Vertices; // shortcut
//--- north, east, south, west errors ----------------------------------------------
float nErr = Math.abs((float) v[n*3+1] - (float) (v[nw*3+1] + v[ne*3+1]) / 2.0f);
float eErr = Math.abs((float) v[e*3+1] - (float) (v[ne*3+1] + v[se*3+1]) / 2.0f);
float sErr = Math.abs((float) v[s*3+1] - (float) (v[se*3+1] + v[sw*3+1]) / 2.0f);
float wErr = Math.abs((float) v[w*3+1] - (float) (v[sw*3+1] + v[nw*3+1]) / 2.0f);
//--- 1. and 2. diagonal error -----------------------------------------------------
float d1Err = Math.abs((float) v[c*3+1] - (float) (v[nw*3+1] + v[se*3+1]) / 2.0f);
float d2Err = Math.abs((float) v[c*3+1] - (float) (v[ne*3+1] + v[sw*3+1]) / 2.0f);
//--- determine max of the 6 errors ------------------------------------------------
float maxErr = Math.max(Math.max(nErr, eErr),
Math.max(Math.max(sErr, wErr), Math.max(d1Err, d2Err)));
return (maxErr / ((float) width * VertexSpacing));
}
private void propagateD2Errors() {
// find the highest level
//--- init vars --------------------------------------------------------------------
int steps = Width / 2;
int width = 2;
int centerX, centerZ;
int w2;
int p1, p2, p3; // indices of parents
int p1x = 0, p1z = 0,
p2x = 0, p2z = 0,
p3x = 0, p3z = 0;
float[] em = ErrorMatrix; // shortcut
//--- iterate through all levels ---------------------------------------------------
while (steps > 1) {
w2 = width / 2;
centerX = w2;
for (int i = 0; i < steps; i++) {
centerZ = w2;
for (int j = 0; j < steps; j++) {
//--- determine parents' indices ------------------------
switch ((centerX/width)%2 + 2*((centerZ/width)%2)) {
case 0: p1x = centerX+w2;
p1z = centerZ+w2;
p2x = centerX-width-w2;
p2z = centerZ+w2;
p3x = centerX+w2;
p3z = centerZ-width-w2;
break;
case 1: p1x = centerX-w2;
p1z = centerZ+w2;
p2x = centerX-w2;
p2z = centerZ-width-w2;
p3x = centerX+width+w2;
p3z = centerZ+w2;
break;
case 2: p1x = centerX+w2;
p1z = centerZ-w2;
p2x = centerX+w2;
p2z = centerZ+width+w2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -