Horde3D
http://horde3d.org/forums/

[Patch] Terrain problem ("step"-like rounding errors)
http://horde3d.org/forums/viewtopic.php?f=3&t=456
Page 1 of 1

Author:  phoenix64 [ 05.08.2008, 22:02 ]
Post subject:  [Patch] Terrain problem ("step"-like rounding errors)

The last days I tried to get horde working with my engine and so far only one direct blocker showed: I couldn't get the terrain to work with my physics.

After some time I notices an irregularity (well, however you call that) in the height data:
http://img145.imageshack.us/my.php?image=stepgb7.png
(look at the flat area where one pixel on the heightmap gets repeated)

I quickly replaced this hack with a better solution (imho):
I just changed it so that only the last pixel now gets repeated, therefore easily allowing to use the terrain because now the error isn't visible any more (and imho this is the best solution unless you allow 2^n+1-Heightmaps.

Patch:
Code:
Index: Source/terrain.cpp                                                   
===================================================================         
--- Source/terrain.cpp  (Revision 31)                                       
+++ Source/terrain.cpp  (Arbeitskopie)                                     
@@ -177,9 +177,9 @@                                                         
                                        if( u == 0 ) s = 0.0f; else if( u == size - 1 ) s = 1.0f;       // Skirt
 
                                        float *vertHeight = &terrain->_heightArray[v * size + u];               
-                                       const float newU = (s * scale + minU) * (terrain->_hmapSize - 1) + 0.5f;
-                                       const float newV = (t * scale + minV) * (terrain->_hmapSize - 1) + 0.5f;
-                                       uint32 index = ((int)newV * terrain->_hmapSize + (int)newU );           
+                                       const float newU = (s * scale + minU) * (terrain->_hmapSize) + 0.5f;   
+                                       const float newV = (t * scale + minV) * (terrain->_hmapSize) + 0.5f;   
+                                       uint32 index = ((int)newV * (terrain->_hmapSize + 1) + (int)newU );     
 
                                        *vertHeight = terrain->_heightData[index] / 65535.0f;                   
 
@@ -312,7 +312,7 @@                                                                                             
                        hmap.getWidth() == 2048 || hmap.getWidth() == 4096 || hmap.getWidth() == 8192) )       
                {                                                                                               
                        _hmapSize = hmap.getWidth();                                                           
-                       _heightData = new unsigned short[_hmapSize * _hmapSize];                               
+                       _heightData = new unsigned short[(_hmapSize + 1) * (_hmapSize + 1)];                   
 
                        float *pixels = hmap.downloadImageData();                                               
 
@@ -326,10 +326,25 @@                                                                                           
                                        height = (unsigned short)(clamp( pixels[(i * _hmapSize + j) * 4], 0, 1 ) * 255 * 256 +
                                                clamp( pixels[(i * _hmapSize + j) * 4 + 1], 0, 1 ) * 255);                   
 
-                                       _heightData[i * _hmapSize + j] = height;                                             
+                                       _heightData[i * (_hmapSize + 1) + j] = height;                                       
                                }                                                                                             
+                       }                                                                                                     
+                       // Fill in last rows (just repeat last texture pixels)                                               
+                       for( uint32 i = 0; i < _hmapSize; ++i )                                                               
+                       {                                                                                                     
+                               unsigned short height;                                                                       
+                                                                                                                             
+                               // Decode 16 bit data from red and green channels                                             
+                               height = (unsigned short)(clamp( pixels[(i * _hmapSize + _hmapSize - 1) * 4], 0, 1 ) * 255 * 256 +
+                                       clamp( pixels[(i * _hmapSize + _hmapSize - 1) * 4 + 1], 0, 1 ) * 255);                   
+                                                                                                                                 
+                               _heightData[i * (_hmapSize + 1) + _hmapSize] = height;                                           
                        }                                                                                                         
-                                                                                                                                 
+                       for( uint32 i = 0; i < _hmapSize + 1; ++i )                                                               
+                       {                                                                                                         
+                               _heightData[_hmapSize * (_hmapSize + 1) + i] = _heightData[(_hmapSize - 1) * (_hmapSize + 1) + i];
+                       }                                                                                                         
+                                                                                                                                 
                        delete[] pixels;                                                                                         
                        return true;                                                                                             
                }                                                                                                                 
@@ -337,8 +352,8 @@                                                                                                               
                {                                                                                                                 
                        // Init default data                                                                                     
                        _hmapSize = 32;                                                                                           
-                       _heightData = new unsigned short[_hmapSize * _hmapSize];                                                 
-                       memset( _heightData, 0, _hmapSize * _hmapSize );                                                         
+                       _heightData = new unsigned short[(_hmapSize + 1) * (_hmapSize + 1)];                                     
+                       memset( _heightData, 0, (_hmapSize + 1) * (_hmapSize + 1) );                                             
                        Modules::log().writeDebugInfo( "Invalid heightmap data in Terrain node %i", _handle );                   
                        return false;                                                                                             
                }                                                                                                                 
@@ -641,15 +656,15 @@                                                                                                             
 
                dir /= dir.length();                                                                                             
 
-               int x = (int)(startX * _hmapSize);                                                                               
-               int y = (int)(startZ * _hmapSize);                                                                               
+               int x = (int)(startX * (_hmapSize + 1));                                                                         
+               int y = (int)(startZ * (_hmapSize + 1));                                                                         
 
                // Check heightmap with Bresenham algorithm (code based on http://de.wikipedia.org/wiki/Bresenham-Algorithmus)
                int t, dx, dy, incX, incY, pdx, pdy, ddx, ddy, err_step_fast, err_step_slow, err;
 
                // Get deltas in image space
-               dx = (int)((endX - startX) * _hmapSize);
-               dy = (int)((endZ - startZ) * _hmapSize);
+               dx = (int)((endX - startX) * (_hmapSize + 1));
+               dy = (int)((endZ - startZ) * (_hmapSize + 1));
 
                // Check directions
                incX = (dx > 0) ? 1 : (dx < 0) ? -1 : 0;
@@ -673,7 +688,7 @@
                // Init error
                err = err_step_slow / 2;
 
-               float height1 = _heightData[y * _hmapSize + x] / 65535.0f, height2;
+               float height1 = _heightData[y * (_hmapSize + 1) + x] / 65535.0f, height2;
 
                Vec3f pos;
                Vec3f prevPos;
@@ -711,7 +726,7 @@
                                x += pdx;
                                y += pdy;
                        }
-                       height2 = _heightData[y * _hmapSize + x] / 65535.0f;
+                       height2 = _heightData[y * (_hmapSize + 1) + x] / 65535.0f;
 
                        pos.x = x / (float)_hmapSize;
                        pos.z = y / (float)_hmapSize;
@@ -810,9 +825,9 @@
                                        float s = (u - 1) * invScale;
                                        if( u == 0 ) s = 0.0f; else if( u == size - 1 ) s = 1.0f;       // Skirt
 
-                                       const float newU = (s * scale + minU) * (_hmapSize - 1) + 0.4f;
-                                       const float newV = (t * scale + minV) * (_hmapSize - 1) + 0.4f;
-                                       uint32 index = (int)newV * _hmapSize + (int)newU;
+                                       const float newU = (s * scale + minU) * _hmapSize + 0.5f;
+                                       const float newV = (t * scale + minV) * _hmapSize + 0.5f;
+                                       uint32 index = (int)newV * (_hmapSize + 1) + (int)newU;
 
                                        *vertData++ = (s * scale + minU);
 
Index: Source/terrain.h
===================================================================
--- Source/terrain.h    (Revision 31)
+++ Source/terrain.h    (Arbeitskopie)
@@ -141,7 +141,7 @@
 
                BoundingBox *getLocalBBox() { return &_localBBox; }
                float getHeight( float x, float y )
-                       { return _heightData[(int)(y * (_hmapSize - 1) + 0.5f) * _hmapSize + (int)(x * (_hmapSize - 1) + 0.5f) ] / 65535.0f; }
+                       { return _heightData[(int)(y * _hmapSize + 0.5f) * (_hmapSize + 1) + (int)(x * _hmapSize + 0.5f) ] / 65535.0f; }
        };
 }

Author:  Volker [ 05.08.2008, 22:09 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

I didn't get it yet,... where is the screenshot and why do you have to add 1 row and column to the heightmap?

Author:  phoenix64 [ 05.08.2008, 22:13 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

Sry, Copy+Paste-fail -.-

The screenshot is there now, this problem has been already seen by someone on irc

EDIT: ARGH!
EDIT2: NOW it works -.-

Author:  swiftcoder [ 05.08.2008, 23:44 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

phoenix64 wrote:
The screenshot is there now, this problem has been already seen by someone on irc
I had noticed that problem before, but thought it was something wrong with the heightmap in the samples. I am generating my own power-of-2 heightmaps (directly in engine), and this problem never shows up. Can we confirm that it is a problem in engine, and not in the exporter?

Author:  phoenix64 [ 06.08.2008, 00:02 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

For me this also happens with the terrain demo (=with heightmaps not generated by me), which most probably don't have exporter errors. Also I load the same heightmap as an ODE trimesh, there I don't get that problem (=the heights begin to differ at the place where Horde3D duplicates a row of pixels).

Author:  Volker [ 06.08.2008, 07:01 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

I submitted the patch to the SVN. I can confirm that this solves gap problems within the terrain sample. But I must admit that I didn't understand in detail why this solves the problem. Currently I don't have time to take a more detailed look at it.
I hope it is indeed a problem in the code and not only in the sample's heightmap data. Nevertheless thanks to phoenix for investigating the problem.

Author:  phoenix64 [ 06.08.2008, 11:19 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

The problem is because of rounding errors, it tries to apply 2^n values to 2^n+1 vertices:
Image
(At least that's my understanding of it. Sry for the crappy image, but I hope it makes it more clear)

Author:  Volker [ 06.08.2008, 12:07 ]
Post subject:  Re: [Patch] Terrain problem ("step"-like rounding errors)

That makes sence, although I though we replicated the original border pixels already. Seems like this was not the case, or we missed something. If I have some time in the future, I will have a further look at it. But thanks again for the patch and the illustrative image ( it is absolutely not crappy :-) )

Page 1 of 1 All times are UTC + 1 hour
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/