Hello guys, it’s me again
I am working on an own try of a way to implement endless terrain. For that I use TerrainPatch objects that are dynamically loaded and saved. My first steps were promising but now I am stuck at the normal edges, showing gaps.
I tried copying the fixNormalEdges method from TerainPatch (can’t use it directly since it’s protected) but it does not work.
I am no pro in such things so it may seem noobish to try it that way, but some help would be really… helpful
Here is how it looks right now (view from the side):
Here is the code I copied from TerrainPatch (I just changed “this.” to “middle.”, rest stays the same):
protected void fixNormalEdges(TerrainPatch middle,
TerrainPatch right,
TerrainPatch bottom,
TerrainPatch top,
TerrainPatch left,
TerrainPatch bottomRight,
TerrainPatch bottomLeft,
TerrainPatch topRight,
TerrainPatch topLeft)
{
Vector3f rootPoint = new Vector3f();
Vector3f rightPoint = new Vector3f();
Vector3f leftPoint = new Vector3f();
Vector3f topPoint = new Vector3f();
Vector3f bottomPoint = new Vector3f();
Vector3f tangent = new Vector3f();
Vector3f binormal = new Vector3f();
Vector3f normal = new Vector3f();
int s = middle.getSize()-1;
if (right != null) { // right side, works its way down
for (int i=0; i<s+1; i++) {
rootPoint.set(0, middle.getHeightmapHeight(s,i), 0);
leftPoint.set(-1, middle.getHeightmapHeight(s-1,i), 0);
rightPoint.set(1, right.getHeightmapHeight(1,i), 0);
if (i == 0) { // top point
bottomPoint.set(0, middle.getHeightmapHeight(s,i+1), 1);
if (top == null) {
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), s, normal, tangent, binormal);
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
} else {
topPoint.set(0, top.getHeightmapHeight(s,s-1), -1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint,normal, tangent, binormal);
setInBuffer(middle.getMesh(), s, normal, tangent, binormal);
setInBuffer(right.getMesh(), 0, normal, tangent, binormal);
setInBuffer(top.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
if (topRight != null) {
// setInBuffer(topRight.getMesh(), (s+1)*s, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
topPoint.set(0, middle.getHeightmapHeight(s,s-1), -1);
if (bottom == null) {
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
setInBuffer(right.getMesh(), (s+1)*(s), normal, tangent, binormal);
} else {
bottomPoint.set(0, bottom.getHeightmapHeight(s,1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
setInBuffer(right.getMesh(), (s+1)*s, normal, tangent, binormal);
setInBuffer(bottom.getMesh(), s, normal, tangent, binormal);
if (bottomRight != null) {
// setInBuffer(bottomRight.getMesh(), 0, normal, tangent, binormal);
}
}
} else { // all in the middle
topPoint.set(0, middle.getHeightmapHeight(s,i-1), -1);
bottomPoint.set(0, middle.getHeightmapHeight(s,i+1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
setInBuffer(right.getMesh(), (s+1)*(i), normal, tangent, binormal);
}
}
}
if (left != null) { // left side, works its way down
for (int i=0; i<s+1; i++) {
rootPoint.set(0, middle.getHeightmapHeight(0,i), 0);
leftPoint.set(-1, left.getHeightmapHeight(s-1,i), 0);
rightPoint.set(1, middle.getHeightmapHeight(1,i), 0);
if (i == 0) { // top point
bottomPoint.set(0, middle.getHeightmapHeight(0,i+1), 1);
if (top == null) {
averageNormalsTangents(null, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), 0, normal, tangent, binormal);
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
} else {
topPoint.set(0, top.getHeightmapHeight(0,s-1), -1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), 0, normal, tangent, binormal);
setInBuffer(left.getMesh(), s, normal, tangent, binormal);
setInBuffer(top.getMesh(), (s+1)*s, normal, tangent, binormal);
if (topLeft != null) {
// setInBuffer(topLeft.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
}
}
} else if (i == s) { // bottom point
topPoint.set(0, middle.getHeightmapHeight(0,i-1), -1);
if (bottom == null) {
averageNormalsTangents(topPoint, rootPoint, leftPoint, null, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(s), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
} else {
bottomPoint.set(0, bottom.getHeightmapHeight(0,1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(s), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(s+1)-1, normal, tangent, binormal);
setInBuffer(bottom.getMesh(), 0, normal, tangent, binormal);
if (bottomLeft != null) {
// setInBuffer(bottomLeft.getMesh(), s, normal, tangent, binormal);
}
}
} else { // all in the middle
topPoint.set(0, middle.getHeightmapHeight(0,i-1), -1);
bottomPoint.set(0, middle.getHeightmapHeight(0,i+1), 1);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(i), normal, tangent, binormal);
setInBuffer(left.getMesh(), (s+1)*(i+1)-1, normal, tangent, binormal);
}
}
}
if (top != null) { // top side, works its way right
for (int i=0; i<s+1; i++) {
rootPoint.set(0, middle.getHeightmapHeight(i,0), 0);
topPoint.set(0, top.getHeightmapHeight(i,s-1), -1);
bottomPoint.set(0, middle.getHeightmapHeight(i,1), 1);
if (i == 0) { // left corner
// handled by left side pass
} else if (i == s) { // right corner
// handled by this patch when it does its right side
} else { // all in the middle
leftPoint.set(-1, middle.getHeightmapHeight(i-1,0), 0);
rightPoint.set(1, middle.getHeightmapHeight(i+1,0), 0);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), i, normal, tangent, binormal);
setInBuffer(top.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
}
}
}
if (bottom != null) { // bottom side, works its way right
for (int i=0; i<s+1; i++) {
rootPoint.set(0, middle.getHeightmapHeight(i,s), 0);
topPoint.set(0, middle.getHeightmapHeight(i,s-1), -1);
bottomPoint.set(0, bottom.getHeightmapHeight(i,1), 1);
if (i == 0) { // left
// handled by the left side pass
} else if (i == s) { // right
// handled by the right side pass
} else { // all in the middle
leftPoint.set(-1, middle.getHeightmapHeight(i-1,s), 0);
rightPoint.set(1, middle.getHeightmapHeight(i+1,s), 0);
averageNormalsTangents(topPoint, rootPoint, leftPoint, bottomPoint, rightPoint, normal, tangent, binormal);
setInBuffer(middle.getMesh(), (s+1)*(s)+i, normal, tangent, binormal);
setInBuffer(bottom.getMesh(), i, normal, tangent, binormal);
}
}
}
}
private void setInBuffer(Mesh mesh, int index, Vector3f normal, Vector3f tangent, Vector3f binormal) {
VertexBuffer NB = mesh.getBuffer(VertexBuffer.Type.Normal);
VertexBuffer TB = mesh.getBuffer(VertexBuffer.Type.Tangent);
VertexBuffer BB = mesh.getBuffer(VertexBuffer.Type.Binormal);
BufferUtils.setInBuffer(normal, (FloatBuffer)NB.getData(), index);
BufferUtils.setInBuffer(tangent, (FloatBuffer)TB.getData(), index);
BufferUtils.setInBuffer(binormal, (FloatBuffer)BB.getData(), index);
NB.setUpdateNeeded();
TB.setUpdateNeeded();
BB.setUpdateNeeded();
}
protected void averageNormalsTangents(
Vector3f topPoint,
Vector3f rootPoint,
Vector3f leftPoint,
Vector3f bottomPoint,
Vector3f rightPoint,
Vector3f normal,
Vector3f tangent,
Vector3f binormal)
{
Vector3f scale = getWorldScale();
Vector3f n1 = new Vector3f(0,0,0);
if (topPoint != null && leftPoint != null) {
n1.set(calculateNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale)));
}
Vector3f n2 = new Vector3f(0,0,0);
if (leftPoint != null && bottomPoint != null) {
n2.set(calculateNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale)));
}
Vector3f n3 = new Vector3f(0,0,0);
if (rightPoint != null && bottomPoint != null) {
n3.set(calculateNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale)));
}
Vector3f n4 = new Vector3f(0,0,0);
if (rightPoint != null && topPoint != null) {
n4.set(calculateNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale)));
}
//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);
normal.set(n1.add(n2).add(n3).add(n4).normalize());
tangent.set(normal.cross(new Vector3f(0,0,1)).normalize());
binormal.set(new Vector3f(1,0,0).cross(normal).normalize());
}
private Vector3f calculateNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {
Vector3f normal = new Vector3f();
normal.set(firstPoint).subtractLocal(rootPoint)
.crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
return normal;
}
Here is the part where I try to connect the patches:
/**
* Attaches a terrain patch to the node. Creates a new patch if necessary
* @param pos the patch pos
*/
public void attachTerrain(Vector2f pos) throws Exception{
if(!isCreated(pos))
this.createTerrain(pos);
TerrainPatch patch = (TerrainPatch) importer.load(new File(cachePath + posToName(pos)));
this.fixNormalEdges(patch,
this.getPatchAtPatchPos(pos.add(new Vector2f(1, 0))),
this.getPatchAtPatchPos(pos.add(new Vector2f(0, -1))),
this.getPatchAtPatchPos(pos.add(new Vector2f(0, 1))),
this.getPatchAtPatchPos(pos.add(new Vector2f(-1, 0))),
this.getPatchAtPatchPos(pos.add(new Vector2f(1, -1))),
this.getPatchAtPatchPos(pos.add(new Vector2f(-1, -1))),
this.getPatchAtPatchPos(pos.add(new Vector2f(1, 1))),
this.getPatchAtPatchPos(pos.add(new Vector2f(-1, 1))));
patch.setMaterial(matNormal);
this.attachChild(patch);
}
Thank you to anyone who takes the time to help me