Browse Source

flipped terrain texture coordinates. New tangent calculations. Warning if heightmap is different size than specified terrain

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8060 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
bre..ns 14 years ago
parent
commit
77718d1f15

+ 63 - 22
engine/src/terrain/com/jme3/terrain/geomipmap/LODGeomap.java

@@ -47,6 +47,7 @@ import com.jme3.scene.Mesh;
 import com.jme3.scene.Mesh.Mode;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.util.BufferUtils;
+import com.jme3.util.TangentBinormalGenerator;
 import java.io.IOException;
 
 /**
@@ -80,10 +81,12 @@ public class LODGeomap extends GeoMap {
         FloatBuffer tb = writeTexCoordArray(null, tcOffset, tcScale, offsetAmount, totalSize);
         FloatBuffer nb = writeNormalArray(null, scale);
         IntBuffer ib = writeIndexArrayLodDiff(null, lod, rightLod, topLod, leftLod, bottomLod);
+        FloatBuffer tanb = writeTangentArray(null, scale);
         Mesh m = new Mesh();
         m.setMode(Mode.TriangleStrip);
         m.setBuffer(Type.Position, 3, pb);
         m.setBuffer(Type.Normal, 3, nb);
+        m.setBuffer(Type.Tangent, 3, tanb);
         m.setBuffer(Type.TexCoord, 2, tb);
         m.setBuffer(Type.Index, 3, ib);
         m.setStatic();
@@ -110,8 +113,8 @@ public class LODGeomap extends GeoMap {
 
         Vector2f tcStore = new Vector2f();
 
-        for (int y = 0; y < getHeight(); y++) {
-
+        // work from bottom of heightmap up, so we don't flip the coords
+        for (int y = getHeight()-1; y >= 0; y--) {
             for (int x = 0; x < getWidth(); x++) {
                 getUV(x, y, tcStore, offset, offsetAmount, totalSize);
                 float tx = tcStore.x * scale.x;
@@ -125,8 +128,8 @@ public class LODGeomap extends GeoMap {
     }
 
     public Vector2f getUV(int x, int y, Vector2f store, Vector2f offset, float offsetAmount, int totalSize) {
-        float offsetX = offset.x + (offsetAmount * 1.0f);//stepScale.x);
-        float offsetY = offset.y + (offsetAmount * 1.0f);//stepScale.z);
+        float offsetX = offset.x + (offsetAmount * 1.0f);
+        float offsetY = -offset.y + (offsetAmount * 1.0f);//note the -, we flip the tex coords
 
         store.set((((float) x) + offsetX) / (float) totalSize, // calculates percentage of texture here
                 (((float) y) + offsetY) / (float) totalSize);
@@ -620,7 +623,44 @@ public class LODGeomap extends GeoMap {
         //System.out.println("Index buffer size: "+num);
         return num;
     }
+    
+    public FloatBuffer writeTangentArray(FloatBuffer store, Vector3f scale) {
+        if (!isLoaded()) {
+            throw new NullPointerException();
+        }
 
+        if (store != null) {
+            if (store.remaining() < getWidth() * getHeight() * 3) {
+                throw new BufferUnderflowException();
+            }
+        } else {
+            store = BufferUtils.createFloatBuffer(getWidth() * getHeight() * 3);
+        }
+        store.rewind();
+        
+        Vector3f tangent = new Vector3f();
+        Vector3f v1 = new Vector3f();
+        Vector3f v2 = new Vector3f();
+        
+        for (int r = 0; r < getHeight(); r++) {
+            for (int c = 0; c < getWidth(); c++) {
+                
+                v1.set(c, getValue(c, r), r);
+                
+                if (c == getWidth()-1) { // last column
+                    v2.set(c+1, getValue(c, r ), r); // use same height
+                } else {
+                    v2.set(c+1, getValue(c+1, r), r);
+                }
+                tangent.set(v2.mult(scale).subtract(v1.mult(scale)));
+                BufferUtils.setInBuffer(tangent, store, (r * getWidth() + c)); // save the tangent
+            }
+        }
+        
+        return store;
+    }
+   
+    
     @Override
     public FloatBuffer writeNormalArray(FloatBuffer store, Vector3f scale) {
         if (!isLoaded()) {
@@ -653,34 +693,34 @@ public class LODGeomap extends GeoMap {
                     if (c == 0) { // first column
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        normal.set(getNormal(bottomPoint, rootPoint, rightPoint));
+                        normal.set(getNormal(bottomPoint, rootPoint, rightPoint, scale));
                     } else if (c == getWidth() - 1) { // last column
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        normal.set(getNormal(leftPoint, rootPoint, bottomPoint));
+                        normal.set(getNormal(leftPoint, rootPoint, bottomPoint, scale));
                     } else { // all middle columns
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        Vector3f n1 = getNormal(leftPoint, rootPoint, bottomPoint);
-                        Vector3f n2 = getNormal(bottomPoint, rootPoint, rightPoint);
+                        Vector3f n1 = getNormal(leftPoint, rootPoint, bottomPoint, scale);
+                        Vector3f n2 = getNormal(bottomPoint, rootPoint, rightPoint, scale);
                         normal.set(n1.add(n2).normalizeLocal());
                     }
                 } else if (r == getHeight() - 1) { // last row
                     if (c == 0) { // first column
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
-                        normal.set(getNormal(rightPoint, rootPoint, topPoint));
+                        normal.set(getNormal(rightPoint, rootPoint, topPoint, scale));
                     } else if (c == getWidth() - 1) { // last column
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
-                        normal.set(getNormal(topPoint, rootPoint, leftPoint));
+                        normal.set(getNormal(topPoint, rootPoint, leftPoint, scale));
                     } else { // all middle columns
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
-                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint);
-                        Vector3f n2 = getNormal(rightPoint, rootPoint, topPoint);
+                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint, scale);
+                        Vector3f n2 = getNormal(rightPoint, rootPoint, topPoint, scale);
                         normal.set(n1.add(n2).normalizeLocal());
                     }
                 } else { // all middle rows
@@ -688,25 +728,25 @@ public class LODGeomap extends GeoMap {
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        Vector3f n1 = getNormal(rightPoint, rootPoint, topPoint);
-                        Vector3f n2 = getNormal(bottomPoint, rootPoint, rightPoint);
+                        Vector3f n1 = getNormal(rightPoint, rootPoint, topPoint, scale);
+                        Vector3f n2 = getNormal(bottomPoint, rootPoint, rightPoint, scale);
                         normal.set(n1.add(n2).normalizeLocal());
                     } else if (c == getWidth() - 1) { // last column
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint);
-                        Vector3f n2 = getNormal(leftPoint, rootPoint, bottomPoint);
+                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint, scale);
+                        Vector3f n2 = getNormal(leftPoint, rootPoint, bottomPoint, scale);
                         normal.set(n1.add(n2).normalizeLocal());
                     } else { // all middle columns
                         topPoint.set(c, getValue(c, r - 1), r - 1);
                         leftPoint.set(c - 1, getValue(c - 1, r), r);
                         rightPoint.set(c + 1, getValue(c + 1, r), r);
                         bottomPoint.set(c, getValue(c, r + 1), r + 1);
-                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint);
-                        Vector3f n2 = getNormal(leftPoint, rootPoint, bottomPoint);
-                        Vector3f n3 = getNormal(bottomPoint, rootPoint, rightPoint);
-                        Vector3f n4 = getNormal(rightPoint, rootPoint, topPoint);
+                        Vector3f n1 = getNormal(topPoint, rootPoint, leftPoint, scale);
+                        Vector3f n2 = getNormal(leftPoint, rootPoint, bottomPoint, scale);
+                        Vector3f n3 = getNormal(bottomPoint, rootPoint, rightPoint, scale);
+                        Vector3f n4 = getNormal(rightPoint, rootPoint, topPoint, scale);
                         normal.set(n1.add(n2).add(n3).add(n4).normalizeLocal());
                     }
                 }
@@ -719,9 +759,10 @@ public class LODGeomap extends GeoMap {
         return store;
     }
 
-    private Vector3f getNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint) {
+    private Vector3f getNormal(Vector3f firstPoint, Vector3f rootPoint, Vector3f secondPoint, Vector3f scale) {
         Vector3f normal = new Vector3f();
-        normal.set(firstPoint).subtractLocal(rootPoint).crossLocal(secondPoint.subtract(rootPoint)).normalizeLocal();
+        //scale = Vector3f.UNIT_XYZ;
+        normal.set(firstPoint.mult(scale)).subtractLocal(rootPoint.mult(scale)).crossLocal(secondPoint.mult(scale).subtract(rootPoint.mult(scale))).normalizeLocal();
         return normal;
     }
 

+ 9 - 5
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainPatch.java

@@ -331,8 +331,11 @@ public class TerrainPatch extends Geometry {
      * recalculate all of this normal vectors in this terrain patch
      */
     protected void updateNormals() {
-        FloatBuffer newNormalBuffer = geomap.writeNormalArray(null, stepScale);
+        TangentBinormalGenerator.generate(this);
+        FloatBuffer newNormalBuffer = geomap.writeNormalArray(null, getWorldScale());
         getMesh().getBuffer(Type.Normal).updateData(newNormalBuffer);
+        FloatBuffer newTangentBuffer = geomap.writeTangentArray(null, getWorldScale());
+        getMesh().getBuffer(Type.Tangent).updateData(newTangentBuffer);
     }
 
     /**
@@ -683,6 +686,7 @@ public class TerrainPatch extends Geometry {
             Vector3f normal,
             Vector3f tangent)
     {
+        Vector3f scale = getWorldScale();
         v[0] = topPoint;
         v[1] = rootPoint;
         v[2] = leftPoint;
@@ -693,7 +697,7 @@ public class TerrainPatch extends Geometry {
         Vector3f t1 = Vector3f.ZERO;
         if (topPoint != null && leftPoint != null) {
             TriangleData td1 = TangentBinormalGenerator.processTriangle(indexes, v, t);
-            n1 = getNormal(topPoint, rootPoint, leftPoint);
+            n1 = getNormal(topPoint.mult(scale), rootPoint.mult(scale), leftPoint.mult(scale));
             t1 = td1.tangent;
         }
         v[0] = leftPoint;
@@ -706,7 +710,7 @@ public class TerrainPatch extends Geometry {
         Vector3f t2 = Vector3f.ZERO;
         if (leftPoint != null && bottomPoint != null) {
             TriangleData td2 = TangentBinormalGenerator.processTriangle(indexes, v, t);
-            n2 = getNormal(leftPoint, rootPoint, bottomPoint);
+            n2 = getNormal(leftPoint.mult(scale), rootPoint.mult(scale), bottomPoint.mult(scale));
             t2 = td2.tangent;
         }
         v[0] = bottomPoint;
@@ -719,7 +723,7 @@ public class TerrainPatch extends Geometry {
         Vector3f t3 = Vector3f.ZERO;
         if (rightPoint != null && bottomPoint != null) {
             TriangleData td3 = TangentBinormalGenerator.processTriangle(indexes, v, t);
-            n3 = getNormal(bottomPoint, rootPoint, rightPoint);
+            n3 = getNormal(bottomPoint.mult(scale), rootPoint.mult(scale), rightPoint.mult(scale));
             t3 = td3.tangent;
         }
         v[0] = rightPoint;
@@ -732,7 +736,7 @@ public class TerrainPatch extends Geometry {
         Vector3f t4 = Vector3f.ZERO;
         if (rightPoint != null && topPoint != null) {
             TriangleData td4 = TangentBinormalGenerator.processTriangle(indexes, v, t);
-            n4 = getNormal(rightPoint, rootPoint, topPoint);
+            n4 = getNormal(rightPoint.mult(scale), rootPoint.mult(scale), topPoint.mult(scale));
             t4 = td4.tangent;
         }
 

+ 17 - 5
engine/src/terrain/com/jme3/terrain/geomipmap/TerrainQuad.java

@@ -67,6 +67,8 @@ import com.jme3.util.TangentBinormalGenerator;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 /**
  * A terrain quad is a node in the quad tree of the terrain system.
@@ -103,6 +105,7 @@ public class TerrainQuad extends Node implements Terrain {
     private BoundingBox affectedAreaBBox; // only set in the root quad
 
     private TerrainPicker picker;
+    private Vector3f lastScale = Vector3f.UNIT_XYZ;
 
     protected ExecutorService executor;
 
@@ -152,6 +155,9 @@ public class TerrainQuad extends Node implements Terrain {
         if (!FastMath.isPowerOfTwo(size - 1)) {
             throw new RuntimeException("size given: " + size + "  Terrain quad sizes may only be (2^N + 1)");
         }
+        if (FastMath.sqrt(heightMap.length) > size) {
+            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!");
+        }
 
         if (heightMap == null)
             heightMap = generateDefaultHeightMap(size);
@@ -728,7 +734,7 @@ public class TerrainQuad extends Node implements Terrain {
         patch1.setModelBound(new BoundingBox());
         patch1.updateModelBound();
         patch1.setLodCalculator(lodCalculatorFactory);
-        TangentBinormalGenerator.generate(patch1);
+        //TangentBinormalGenerator.generate(patch1);
 
         // 2 lower left
         float[] heightBlock2 = createHeightSubBlock(heightMap, 0, split - 1,
@@ -750,7 +756,7 @@ public class TerrainQuad extends Node implements Terrain {
         patch2.setModelBound(new BoundingBox());
         patch2.updateModelBound();
         patch2.setLodCalculator(lodCalculatorFactory);
-        TangentBinormalGenerator.generate(patch2);
+        //TangentBinormalGenerator.generate(patch2);
 
         // 3 upper right
         float[] heightBlock3 = createHeightSubBlock(heightMap, split - 1, 0,
@@ -772,7 +778,7 @@ public class TerrainQuad extends Node implements Terrain {
         patch3.setModelBound(new BoundingBox());
         patch3.updateModelBound();
         patch3.setLodCalculator(lodCalculatorFactory);
-        TangentBinormalGenerator.generate(patch3);
+        //TangentBinormalGenerator.generate(patch3);
 
         // 4 lower right
         float[] heightBlock4 = createHeightSubBlock(heightMap, split - 1,
@@ -794,7 +800,7 @@ public class TerrainQuad extends Node implements Terrain {
         patch4.setModelBound(new BoundingBox());
         patch4.updateModelBound();
         patch4.setLodCalculator(lodCalculatorFactory);
-        TangentBinormalGenerator.generate(patch4);
+        //TangentBinormalGenerator.generate(patch4);
     }
 
     public float[] createHeightSubBlock(float[] heightMap, int x,
@@ -870,7 +876,13 @@ public class TerrainQuad extends Node implements Terrain {
     }
 
     protected boolean needToRecalculateNormals() {
-        return affectedAreaBBox != null;
+        if (affectedAreaBBox != null)
+            return true;
+        if (!lastScale.equals(getWorldScale())) {
+            lastScale = getWorldScale();
+            return true;
+        }
+        return false;
     }
 
     public float getHeightmapHeight(Vector2f xz) {