Просмотр исходного кода

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 13 лет назад
Родитель
Сommit
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)
             float h = heights[y*width + x];
             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;
-            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);
     }

+ 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)
         {
-            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)
 {
     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,
         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.
     void addConstraint(PhysicsRigidBody* a, PhysicsRigidBody* b, PhysicsConstraint* constraint);