Currently showing src/TerrainShape.java
package com.janusresearch.concept.Xith3DTerrainLightingTest;
import javax.vecmath.*;
import com.xith3d.loaders.texture.TextureLoader;
import com.xith3d.scenegraph.*;
import com.xith3d.terrain.Terrain;
/**
* TerrainShape is a Xith scenegraph BranchGroup containing terrain geometry.
*
* Xith's <code>terrain.render()</code> gave us an IndexedTriangleArray as our
* terrain's geometry object, which is terribly inefficient. The reason Xith did
* this was to allow for future division of adaptive quads for level of detail,
* but we don't plan on implementing that any time soon. For our purposes, the
* IndexedTriangleArray from Xith's implementation sucks as we're storing 12
* vertices for each 32x32 square but only dividing the squares into 4
* triangles. For every vertex, we're storing coordinates, a color, a normal,
* and a texture coordinate. This all adds up and most definitely takes its toll
* on system resources. I switched away from Xith's TerrainRenderInterface and
* went with a TriangleStripArray setup. The triangle strips allow us to break
* the same 32x32 square up into 8 triangles (twice the number of the old
* implementation) using the same number of vertices (12).
* </p>
*
* <p>
* As always, there is a trade-off between performance and beauty. By default,
* the scaling is set to 16, meaning the two "legs" of our right triangles are
* 16 (hyp = sqrt(2) * 16). This gives us twice the number of triangles as we
* previously had using roughly the same number of vertices to do it. If you
* want to improve performance (sacrificing beauty), increase this scale value
* to 32 or something larger.
* </p>
*
* @author mwright
*/
public class TerrainShape extends BranchGroup {
Terrain terrain;
int MAX_HEIGHT = 400;
int defaultScale = 16;
int totalVertexCount = 0;
Shape3D shape;
PolygonAttributes pa;
TextureAttributes texAttribs;
TransparencyAttributes transAttrib;
TriangleStripArray geo;
public TerrainShape(Terrain terrain) {
this.terrain = terrain;
setName("Terrain Shape");
buildShape();
}
private void buildShape() {
int numStrips = terrain.getWidth() / defaultScale;
int numVertsPerStrip = (numStrips + 1) * 2;
int stripVertexCounts[] = new int[numStrips];
for (int i = 0; i < stripVertexCounts.length; i++) {
stripVertexCounts[i] = numVertsPerStrip;
}
geo = new TriangleStripArray(numStrips * numVertsPerStrip, TriangleStripArray.COORDINATES
| TriangleStripArray.NORMALS
| GeometryArray.COLOR_3
| GeometryArray.TEXTURE_COORDINATE_2, stripVertexCounts);
for (int x = 0; (x + defaultScale) <= terrain.getWidth(); x += defaultScale) {
for (int z = 0; z <= terrain.getDepth(); z += defaultScale) {
initVert(totalVertexCount, x, terrain.getY(x, z), z);
totalVertexCount++;
initVert(totalVertexCount, x + defaultScale, terrain.getY(x + defaultScale, z), z);
totalVertexCount++;
}
}
Appearance a = new Appearance();
pa = new PolygonAttributes();
pa.setPolygonMode(PolygonAttributes.POLYGON_FILL);
a.setPolygonAttributes(pa);
Material mat = new Material();
mat.setLightingEnable(true);
mat.setAmbientColor(1.f, 1.f, 1.f);
mat.setDiffuseColor(1.f, 1.f, 1.f);
mat.setSpecularColor(0.f, 0.f, 0.f);
a.setMaterial(mat);
Texture2D texture = (Texture2D) TextureLoader.tf.getMinMapTexture("stone.jpg");
a.setTexture(texture);
shape = new Shape3D(geo, a);
shape.setBoundsAutoCompute(false);
shape.setBounds(new BoundingSphere(new Point3f(0, 0, 0), 100000));
this.addChild(shape);
}
public void initVert(int counter, float x, float y, float z) {
int texSize = 512;
int texScale = terrain.getWidth() / texSize;
float texCoordx, texCoordz;
texCoordx = x / (terrain.getWidth() / texScale);
texCoordz = z / (terrain.getWidth() / texScale);
TexCoord2f texCoord = new TexCoord2f(texCoordz, texCoordx);
geo.setCoordinate(x, y, z);
geo.setTextureCoordinate(0, counter, texCoord);
geo.setColor(1.f, 1.f, 1.f);
geo.setNormal(calculateNormal(x, y, z));
}
public Vector3f calculateNormal(float x, float y, float z) {
int vectorCalcRadius = defaultScale;
Point3f a = new Point3f(x, y, z);
Point3f b = new Point3f(x, terrain.getY(x, (z + vectorCalcRadius)), z + vectorCalcRadius);
Point3f c = new Point3f(x + vectorCalcRadius, terrain.getY((x + vectorCalcRadius), (z + vectorCalcRadius)), z + vectorCalcRadius);
Point3f d = new Point3f(x + vectorCalcRadius, terrain.getY((x + vectorCalcRadius), z), z);
Point3f e = new Point3f(x + vectorCalcRadius, terrain.getY((x + vectorCalcRadius), (z - vectorCalcRadius)), z - vectorCalcRadius);
Point3f f = new Point3f(x, terrain.getY(x, (z - vectorCalcRadius)), z - vectorCalcRadius);
Point3f g = new Point3f(x - vectorCalcRadius, terrain.getY((x - vectorCalcRadius), (z - vectorCalcRadius)), z - vectorCalcRadius);
Point3f h = new Point3f(x - vectorCalcRadius, terrain.getY((x - vectorCalcRadius), z), z);
Point3f i = new Point3f(x - vectorCalcRadius, terrain.getY((x - vectorCalcRadius), (z + vectorCalcRadius)), z + vectorCalcRadius);
Vector3f ab = new Vector3f();
Vector3f ac = new Vector3f();
Vector3f ad = new Vector3f();
Vector3f ae = new Vector3f();
Vector3f af = new Vector3f();
Vector3f ag = new Vector3f();
Vector3f ah = new Vector3f();
Vector3f ai = new Vector3f();
ab.sub(a, b);
ac.sub(a, c);
ad.sub(a, d);
ae.sub(a, e);
af.sub(a, f);
ag.sub(a, g);
ah.sub(a, h);
ai.sub(a, i);
Vector3f bc = new Vector3f();
Vector3f cd = new Vector3f();
Vector3f de = new Vector3f();
Vector3f ef = new Vector3f();
Vector3f fg = new Vector3f();
Vector3f gh = new Vector3f();
Vector3f hi = new Vector3f();
Vector3f ib = new Vector3f();
bc.cross(ab, ac);
cd.cross(ac, ad);
de.cross(ad, ae);
ef.cross(ae, af);
fg.cross(af, ag);
gh.cross(ag, ah);
hi.cross(ah, ai);
ib.cross(ai, ab);
bc.normalize();
cd.normalize();
de.normalize();
ef.normalize();
fg.normalize();
gh.normalize();
hi.normalize();
ib.normalize();
Vector3f n = new Vector3f();
n.add(bc);
n.add(cd);
n.add(de);
n.add(ef);
n.add(fg);
n.add(gh);
n.add(hi);
n.add(ib);
n.normalize();
return n;
}
/**
* @param line
* If true, then draw the terrain in wireframe mode. Otherwise draw
* the terrain filled.
*/
public void setLineMode(boolean line) {
if (line)
pa.setPolygonMode(PolygonAttributes.POLYGON_LINE);
else
pa.setPolygonMode(PolygonAttributes.POLYGON_FILL);
}
public boolean getLineMode() {
if (pa.getPolygonMode() == PolygonAttributes.POLYGON_LINE)
return true;
else
return false;
}
}
Total 266 Lines of Code.
|
Source code formatted using showsrc by William Denniss
|