Parcourir la source

Change heightmap format from grayscale to packed RGB. Maintain compatibility with grayscale PNGs, but at the lower precision of course. Confirmed that the internal heightmap test is unaffected by this change. Also tested with experimental terrain that has a larger vertical range. NOTE: Includes a change to gameplay-encoder source code; please rebuild gameplay-encoder executables from this new source.

Ken Whatmough il y a 13 ans
Parent
commit
bbf4b1f344

+ 7 - 3
gameplay-encoder/src/Mesh.cpp

@@ -225,10 +225,14 @@ void Mesh::generateHeightmap(const char* filename)
             // Write height value normalized between 0-255 (between min and max height)
             // Write height value normalized between 0-255 (between min and max height)
             float h = heights[y*width + x];
             float h = heights[y*width + x];
             float nh = (h - minHeight) / maxHeight;
             float nh = (h - minHeight) / maxHeight;
-            png_byte b = (png_byte)(nh * 255.0f);
-            
+            int bits = (int)(nh * 16777215.0f); // 2^24-1
+
             int pos = x*3;
             int pos = x*3;
-            row[pos] = row[pos+1] = row[pos+2] = b;
+            row[pos+2] = (png_byte)(bits & 0xff);
+            bits >>= 8;
+            row[pos+1] = (png_byte)(bits & 0xff);
+            bits >>= 8;
+            row[pos] = (png_byte)(bits & 0xff);
         }
         }
         png_write_row(png_ptr, row);
         png_write_row(png_ptr, row);
     }
     }

+ 25 - 3
gameplay/src/PhysicsController.cpp

@@ -1057,9 +1057,21 @@ PhysicsCollisionShape* PhysicsController::createHeightfield(Node* node, Image* i
     {
     {
         for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
         for (unsigned int y = 0, h = image->getHeight(); y < h; ++y)
         {
         {
-            heights[x + y * w] = ((((float)data[(x + y * h) * pixelSize + 0]) +
-                ((float)data[(x + y * h) * pixelSize + 1]) +
-                ((float)data[(x + y * h) * pixelSize + 2])) / 768.0f) * (maxHeight - minHeight) + minHeight;
+            //
+            // Orignially in GamePlay this was normalizedHeightGrayscale which generally yielded
+            // only 8-bit precision. This has been replaced by normalizedHeightPacked (with a
+            // corresponding change in gameplay-encoder).
+            //
+            // BACKWARD COMPATIBILITY
+            // In grayscale images where r=g=b this will maintain some degree of compatibility,
+            // to within 0.4%. This can be seen by setting r=g=b=x and comparing the grayscale
+            // height expression to the packed height expression: the error is 2^-8 + 2^-16
+            // which is just under 0.4%.
+            //
+            heights[x + y * w] = normalizedHeightPacked(
+                data[(x + y * h) * pixelSize + 0],
+                data[(x + y * h) * pixelSize + 1],
+                data[(x + y * h) * pixelSize + 2]) * (maxHeight - minHeight) + minHeight;
         }
         }
     }
     }
 
 
@@ -1382,6 +1394,16 @@ float PhysicsController::calculateHeight(float* data, unsigned int width, unsign
     }
     }
 }
 }
 
 
+float PhysicsController::normalizedHeightGrayscale(float r, float g, float b)
+{
+    return (r + g + b) / 768.0f;
+}
+
+float PhysicsController::normalizedHeightPacked(float r, float g, float b)
+{
+    return (256.0f*r + g + 0.00390625f*b) / 65536.0f;
+}
+
 void PhysicsController::addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 void PhysicsController::addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint)
 {
 {
     GP_ASSERT(a);
     GP_ASSERT(a);

+ 6 - 0
gameplay/src/PhysicsController.h

@@ -457,6 +457,12 @@ private:
     static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y,
     static float calculateHeight(float* data, unsigned int width, unsigned int height, float x, float y,
         const Matrix* worldMatrix = NULL, Vector3* normalData = NULL, Vector3* normalResult = NULL);
         const Matrix* worldMatrix = NULL, Vector3* normalData = NULL, Vector3* normalResult = NULL);
 
 
+    // Legacy method for grayscale heightmaps: r + g + b, normalized.
+    static float normalizedHeightGrayscale(float r, float g, float b);
+
+    // Higher precision method for heightmaps: 65536*r + 256*g + b, normalized.
+    static float normalizedHeightPacked(float r, float g, float b);
+
     // Sets up the given constraint for the given two rigid bodies.
     // Sets up the given constraint for the given two rigid bodies.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);