package framework.model3D;
import java3d.Appearance;
import java3d.BoundingBox;
import java3d.Shape3D;
import java3d.IndexedTriangleStripArray;
import java3d.TriangleStripArray;
import java3d.Point3d;
import java3d.Vector3d;
import java3d.Vector3f;
public class Terrain3D extends BaseObject3D {
static final int MESH_SIZE = 4;
private Position3D origin;
private double sizeX = 0;
private double sizeZ = 0;
private double heightMap[][] = null;
private int meshX = 0;
private int meshZ = 0;
private TriangleStripArray triStripAttay = null;
public Terrain3D(Position3D origin, double sizeX, double sizeZ, double heightMap[][], Appearance a) {
super();
this.origin = origin;
this.sizeX = sizeX;
this.sizeZ = sizeZ;
this.heightMap = heightMap;
meshX = heightMap[0].length;
meshZ = heightMap.length;
int stripVertexCounts[] = new int[meshZ - 1];
for (int n = 0; n < meshZ - 1; n++) {
stripVertexCounts[n] = meshX * 2;
}
triStripAttay = new TriangleStripArray(meshX * 2 * (meshZ - 1),
TriangleStripArray.COORDINATES | TriangleStripArray.NORMALS,
stripVertexCounts);
int index = 0;
for (int z = 0; z < meshZ; z++) {
for (int x = 0; x < meshX; x++) {
// メッシュごとに三角形を2つづつ生成
if (z < meshZ - 1) {
// 頂点座標の設定
// 頂点の法線ベクトルの設定
triStripAttay.setCoordinate(index,
new Point3d(origin.getX() + sizeX * (double)x,
origin.getY() + heightMap[z][x],
origin.getZ() + sizeZ * (double)z));
Vector3f normal = calcNormal(z, x);
normal.normalize();
triStripAttay.setNormal(index, normal);
triStripAttay.setCoordinate(index + 1,
new Point3d(origin.getX() + sizeX * (double)x,
origin.getY() + heightMap[z + 1][x],
origin.getZ() + sizeZ * (double)(z + 1)));
normal = calcNormal(z + 1, x);
normal.normalize();
triStripAttay.setNormal(index + 1, normal);
index += 2;
}
}
}
Appearance a2 = (Appearance)a.cloneNodeComponent();
Shape3D shape = new Shape3D(triStripAttay, a2);
center.addChild(shape);
}
private Vector3f calcNormal(int z, int x) {
Vector3f normal = new Vector3f();
if (x < meshX - 1) {
Vector3f xp = new Vector3f((float)sizeX, (float)(heightMap[z][x+1] - heightMap[z][x]), 0.0f);
if (z < meshZ - 1) {
Vector3f zp = new Vector3f(0.0f, (float)(heightMap[z+1][x] - heightMap[z][x]), (float)sizeZ);
Vector3f v1 = new Vector3f();
v1.cross(zp, xp);
v1.normalize();
normal.add(v1);
}
if (z > 0) {
Vector3f zm = new Vector3f(0.0f, (float)(heightMap[z-1][x] - heightMap[z][x]), -(float)sizeZ);
Vector3f v1 = new Vector3f();
v1.cross(xp, zm);
v1.normalize();
normal.add(v1);
}
}
if (x > 0) {
Vector3f xm = new Vector3f(-(float)sizeX, (float)(heightMap[z][x-1] - heightMap[z][x]), 0.0f);
if (z < meshZ - 1) {
Vector3f zp = new Vector3f(0.0f, (float)(heightMap[z+1][x] - heightMap[z][x]), (float)sizeZ);
Vector3f v1 = new Vector3f();
v1.cross(xm, zp);
v1.normalize();
normal.add(v1);
}
if (z > 0) {
Vector3f zm = new Vector3f(0.0f, (float)(heightMap[z-1][x] - heightMap[z][x]), -(float)sizeZ);
Vector3f v1 = new Vector3f();
v1.cross(zm, xm);
v1.normalize();
normal.add(v1);
}
}
return normal;
}
public BoundingSurface[] getBoundingSurfaces() {
if (boundingSurfaces == null) {
if (triStripAttay == null) return null;
double coordinate1[] = new double[3];
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = new double[3];
// GeometryArrayの習得
if (triStripAttay instanceof TriangleStripArray) {
// IndexedTriangleStripArray の場合
// 8 x 8 メッシュ単位でまとめる
BoundingSurface surfaces[] = new BoundingSurface[((meshX + MESH_SIZE - 2) / MESH_SIZE) * ((meshZ + MESH_SIZE - 2) / MESH_SIZE)];
int n = 0;
for (int j = 0; j < meshZ - 1; j += MESH_SIZE) {
for (int i = 0; i < meshX - 1; i += MESH_SIZE) {
BoundingSurface parent = new BoundingSurface();
double lowY = 1.0;
double highY = -1.0;
for (int j2 = 0; j + j2 < meshZ - 1 && j2 < MESH_SIZE; j2++) {
for (int i2 = 0; i + i2 < meshX - 1 && i2 < MESH_SIZE; i2++) {
int index = (j + j2) * meshX * 2 + (i + i2) * 2;
triStripAttay.getCoordinates(index, coordinate1);
triStripAttay.getCoordinates(index + 1, coordinate2);
triStripAttay.getCoordinates(index + 2, coordinate3);
triStripAttay.getCoordinates(index + 3, coordinate4);
if (lowY > highY) {
lowY = highY = coordinate1[1];
} else {
if (lowY > coordinate1[1]) {
lowY = coordinate1[1];
} else if (highY < coordinate1[1]) {
highY = coordinate1[1];
}
if (lowY > coordinate2[1]) {
lowY = coordinate2[1];
} else if (highY < coordinate2[1]) {
highY = coordinate2[1];
}
if (lowY > coordinate3[1]) {
lowY = coordinate3[1];
} else if (highY < coordinate3[1]) {
highY = coordinate3[1];
}
if (lowY > coordinate4[1]) {
lowY = coordinate4[1];
} else if (highY < coordinate4[1]) {
highY = coordinate4[1];
}
}
// 1 x 1 メッシュ内のBoundingSurface
Vector3d v1 = new Vector3d(coordinate1);
Vector3d v2 = new Vector3d(coordinate2);
Vector3d v3 = new Vector3d(coordinate3);
Vector3d v4 = new Vector3d(coordinate4);
BoundingSurface bSurface = new BoundingSurface();
bSurface.addVertex((Vector3d)v1.clone()); //1つめの三角形
bSurface.addVertex((Vector3d)v2.clone());
bSurface.addVertex((Vector3d)v3.clone());
bSurface.setBounds(createBoundingPolytope(v1, v2, v3));
parent.addChild(bSurface, false);
bSurface = new BoundingSurface();
bSurface.addVertex((Vector3d)v2.clone()); //2つめの三角形
bSurface.addVertex((Vector3d)v4.clone());
bSurface.addVertex((Vector3d)v3.clone());
bSurface.setBounds(createBoundingPolytope(v2, v4, v3));
parent.addChild(bSurface, true);
}
}
// 8 x 8 メッシュ単位のBoundingSurface
triStripAttay.getCoordinates(j * meshX * 2 + i * 2, coordinate1);
parent.setBounds(new BoundingBox(new Point3d(coordinate1[0], lowY, coordinate1[2]),
new Point3d(coordinate4[0], highY, coordinate4[2])));
surfaces[n] = parent;
n++;
}
}
boundingSurfaces = surfaces;
} else {
return null;
}
}
return boundingSurfaces;
}
public double getHeight(double x, double z) {
int i = (int)((x - origin.getX()) / sizeX);
int j = (int)((z - origin.getZ()) / sizeZ);
if (i >= meshX || i < 0 || j >= meshZ || j < 0) return 0.0;
int index = j * meshX * 2 + i * 2;
double coordinate1[] = new double[3];
double coordinate2[] = new double[3];
double coordinate3[] = new double[3];
double coordinate4[] = new double[3];
triStripAttay.getCoordinates(index, coordinate1);
triStripAttay.getCoordinates(index + 1, coordinate2);
triStripAttay.getCoordinates(index + 2, coordinate3);
triStripAttay.getCoordinates(index + 3, coordinate4);
Vector3d v1 = new Vector3d(coordinate1);
Vector3d v2 = new Vector3d(coordinate2);
Vector3d v3 = new Vector3d(coordinate3);
Vector3d v4 = new Vector3d(coordinate4);
Vector3d p1 = new Vector3d(x, 0.0, z);
Vector3d p2 = new Vector3d(x, 1.0, z);
double x2 = x - (double)i * sizeX - origin.getX();
double z2 = z - (double)j * sizeZ - origin.getZ();
if (x2 < GeometryUtility.TOLERANCE || (meshZ - z2) / x2 > meshZ / meshX) {
// 1つめの三角形を通る場合
Vector3d crossPoint = GeometryUtility.intersect(GeometryUtility.createPlane(v1, v2, v3), p1, p2);
return crossPoint.getY();
} else {
// 2つめの三角形を通る場合
Vector3d crossPoint = GeometryUtility.intersect(GeometryUtility.createPlane(v2, v4, v3), p1, p2);
return crossPoint.getY();
}
}
}
//
// ********** IndexedTriangleStripArray を使うバージョン **********
// (IndexedTriangleStripArrayを用いるとメモリを節約できるが、シェーディングができないので注意)
//
//public class Terrain3D extends BaseObject3D {
// static final int MESH_SIZE = 8;
// private Position3D origin;
// private double sizeX = 0;
// private double sizeZ = 0;
// private double heightMap[][] = null;
// private int meshX = 0;
// private int meshZ = 0;
// private IndexedTriangleStripArray triStripAttay = null;
//
// public Terrain3D(Position3D origin, double sizeX, double sizeZ, double heightMap[][], Appearance a) {
// super();
// this.origin = origin;
// this.sizeX = sizeX;
// this.sizeZ = sizeZ;
// this.heightMap = heightMap;
// meshX = heightMap[0].length;
// meshZ = heightMap.length;
//
// int stripVertexCounts[] = new int[meshZ - 1];
// for (int n = 0; n < meshZ - 1; n++) {
// stripVertexCounts[n] = meshX * 2;
// }
// triStripAttay = new IndexedTriangleStripArray(meshX * meshZ,
// IndexedTriangleStripArray.COORDINATES | IndexedTriangleStripArray.NORMALS,
// meshX * 2 * (meshZ - 1),
// stripVertexCounts);
// int index = 0, index2 = 0, i1, i2;
// for (int z = 0; z < meshZ; z++) {
// for (int x = 0; x < meshX; x++) {
// // 頂点座標の設定
// triStripAttay.setCoordinate(index,
// new Point3d(origin.getX() + sizeX * (double)x,
// origin.getY() + heightMap[z][x],
// origin.getZ() + sizeZ * (double)z));
// // 頂点の法線ベクトルの設定
// Vector3f normal = new Vector3f();
// if (x < meshX - 1) {
// Vector3f xp = new Vector3f((float)sizeX, (float)(heightMap[z][x+1] - heightMap[z][x]), 0.0f);
// if (z < meshZ - 1) {
// Vector3f zp = new Vector3f(0.0f, (float)(heightMap[z+1][x] - heightMap[z][x]), (float)sizeZ);
// Vector3f v1 = new Vector3f();
// v1.cross(zp, xp);
// v1.normalize();
// normal.add(v1);
// }
// if (z > 0) {
// Vector3f zm = new Vector3f(0.0f, (float)(heightMap[z-1][x] - heightMap[z][x]), -(float)sizeZ);
// Vector3f v1 = new Vector3f();
// v1.cross(xp, zm);
// v1.normalize();
// normal.add(v1);
// }
// }
// if (x > 0) {
// Vector3f xm = new Vector3f(-(float)sizeX, (float)(heightMap[z][x-1] - heightMap[z][x]), 0.0f);
// if (z < meshZ - 1) {
// Vector3f zp = new Vector3f(0.0f, (float)(heightMap[z+1][x] - heightMap[z][x]), (float)sizeZ);
// Vector3f v1 = new Vector3f();
// v1.cross(xm, zp);
// v1.normalize();
// normal.add(v1);
// }
// if (z > 0) {
// Vector3f zm = new Vector3f(0.0f, (float)(heightMap[z-1][x] - heightMap[z][x]), -(float)sizeZ);
// Vector3f v1 = new Vector3f();
// v1.cross(zm, xm);
// v1.normalize();
// normal.add(v1);
// }
// }
// normal.normalize();
// triStripAttay.setNormal(index, normal);
// index++;
// // メッシュごとに三角形を2つづつ生成
// if (z < meshZ - 1) {
// i1 = z * meshX + x;
// i2 = (z + 1) * meshX + x;
// triStripAttay.setCoordinateIndices(index2, new int[]{i1, i2});
// index2 += 2;
// }
// }
// }
// Appearance a2 = (Appearance)a.cloneNodeComponent(true);
// a2.setCapability(Appearance.ALLOW_MATERIAL_READ);
// a2.setCapability(Appearance.ALLOW_TEXTURE_READ);
// a2.setCapability(Appearance.ALLOW_TEXTURE_WRITE);
// a2.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_READ);
// a2.setCapability(Appearance.ALLOW_TEXTURE_ATTRIBUTES_WRITE);
// Shape3D shape = new Shape3D(triStripAttay, a2);
// shape.setCapability(Shape3D.ALLOW_APPEARANCE_READ);
// shape.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE);
// center.addChild(shape);
// }
//
// public BoundingSurface[] getBoundingSurfaces() {
// if (boundingSurfaces == null) {
// if (triStripAttay == null) return null;
// double coordinate1[] = new double[3];
// double coordinate2[] = new double[3];
// double coordinate3[] = new double[3];
// double coordinate4[] = new double[3];
//
// // GeometryArrayの習得
// if (triStripAttay instanceof IndexedTriangleStripArray) {
// // IndexedTriangleStripArray の場合
// // 8 x 8 メッシュ単位でまとめる
// BoundingSurface surfaces[] = new BoundingSurface[((meshX + MESH_SIZE - 2) / MESH_SIZE) * ((meshZ + MESH_SIZE - 2) / MESH_SIZE)];
// int n = 0;
// for (int j = 0; j < meshZ - 1; j += MESH_SIZE) {
// for (int i = 0; i < meshX - 1; i += MESH_SIZE) {
// BoundingSurface parent = new BoundingSurface();
// double lowY = 1.0;
// double highY = -1.0;
// for (int j2 = 0; j + j2 < meshZ - 1 && j2 < MESH_SIZE; j2++) {
// for (int i2 = 0; i + i2 < meshX - 1 && i2 < MESH_SIZE; i2++) {
// int index = (j + j2) * meshX * 2 + (i + i2) * 2;
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index), coordinate1);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+1), coordinate2);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+2), coordinate3);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+3), coordinate4);
// if (lowY > highY) {
// lowY = highY = coordinate1[1];
// } else {
// if (lowY > coordinate1[1]) {
// lowY = coordinate1[1];
// } else if (highY < coordinate1[1]) {
// highY = coordinate1[1];
// }
// if (lowY > coordinate2[1]) {
// lowY = coordinate2[1];
// } else if (highY < coordinate2[1]) {
// highY = coordinate2[1];
// }
// if (lowY > coordinate3[1]) {
// lowY = coordinate3[1];
// } else if (highY < coordinate3[1]) {
// highY = coordinate3[1];
// }
// if (lowY > coordinate4[1]) {
// lowY = coordinate4[1];
// } else if (highY < coordinate4[1]) {
// highY = coordinate4[1];
// }
// }
//
// // 1 x 1 メッシュ内のBoundingSurface
// Vector3d v1 = new Vector3d(coordinate1);
// Vector3d v2 = new Vector3d(coordinate2);
// Vector3d v3 = new Vector3d(coordinate3);
// Vector3d v4 = new Vector3d(coordinate4);
// BoundingSurface bSurface = new BoundingSurface();
// bSurface.addVertex((Vector3d)v1.clone()); //1つめの三角形
// bSurface.addVertex((Vector3d)v2.clone());
// bSurface.addVertex((Vector3d)v3.clone());
// bSurface.setBounds(createBoundingPolytope(v1, v2, v3));
// parent.addChild(bSurface, false);
//
// bSurface = new BoundingSurface();
// bSurface.addVertex((Vector3d)v2.clone()); //2つめの三角形
// bSurface.addVertex((Vector3d)v4.clone());
// bSurface.addVertex((Vector3d)v3.clone());
// bSurface.setBounds(createBoundingPolytope(v2, v4, v3));
// parent.addChild(bSurface, true);
// }
// }
// // 8 x 8 メッシュ単位のBoundingSurface
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(j * meshX * 2 + i * 2), coordinate1);
// parent.setBounds(new BoundingBox(new Point3d(coordinate1[0], lowY, coordinate1[2]),
// new Point3d(coordinate4[0], highY, coordinate4[2])));
// surfaces[n] = parent;
// n++;
// }
// }
// boundingSurfaces = surfaces;
// } else {
// return null;
// }
// }
// return boundingSurfaces;
// }
//
// public double getHeight(double x, double z) {
// int i = (int)((x - origin.getX()) / sizeX);
// int j = (int)((z - origin.getZ()) / sizeZ);
// if (i >= meshX || i < 0 || j >= meshZ || j < 0) return 0.0;
//
// int index = j * meshX * 2 + i * 2;
// double coordinate1[] = new double[3];
// double coordinate2[] = new double[3];
// double coordinate3[] = new double[3];
// double coordinate4[] = new double[3];
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index), coordinate1);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+1), coordinate2);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+2), coordinate3);
// triStripAttay.getCoordinates(triStripAttay.getCoordinateIndex(index+3), coordinate4);
// Vector3d v1 = new Vector3d(coordinate1);
// Vector3d v2 = new Vector3d(coordinate2);
// Vector3d v3 = new Vector3d(coordinate3);
// Vector3d v4 = new Vector3d(coordinate4);
// Vector3d p1 = new Vector3d(x, 0.0, z);
// Vector3d p2 = new Vector3d(x, 1.0, z);
//
// double x2 = x - (double)i * sizeX - origin.getX();
// double z2 = z - (double)j * sizeZ - origin.getZ();
// if (x2 < GeometryUtility.TOLERANCE || (meshZ - z2) / x2 > meshZ / meshX) {
// // 1つめの三角形を通る場合
// Vector3d crossPoint = GeometryUtility.intersect(GeometryUtility.createPlane(v1, v2, v3), p1, p2);
// return crossPoint.getY();
// } else {
// // 2つめの三角形を通る場合
// Vector3d crossPoint = GeometryUtility.intersect(GeometryUtility.createPlane(v2, v4, v3), p1, p2);
// return crossPoint.getY();
// }
// }
//}