Skip to content

Commit cf24e65

Browse files
committedNov 11, 2018
Calculate normals of terrain tile vertices
1 parent eab40d0 commit cf24e65

File tree

3 files changed

+68
-23
lines changed

3 files changed

+68
-23
lines changed
 

‎src/3d/terrain/qgsdemterraintilegeometry_p.cpp

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
using namespace Qt3DRender;
2828

2929

30-
static QByteArray createPlaneVertexData( int res, float skirtHeight, const QByteArray &heights )
30+
static QByteArray createPlaneVertexData( int res, float side, float vertScale, float skirtHeight, const QByteArray &heights )
3131
{
3232
Q_ASSERT( res >= 2 );
3333
Q_ASSERT( heights.count() == res * res * static_cast<int>( sizeof( float ) ) );
@@ -58,17 +58,20 @@ static QByteArray createPlaneVertexData( int res, float skirtHeight, const QByte
5858
// as we do not create valid triangles that would use such vertices
5959
const float noDataHeight = 0;
6060

61+
const int iMax = resolution.width() - 1;
62+
const int jMax = resolution.height() - 1;
63+
6164
// Iterate over z
6265
for ( int j = -1; j <= resolution.height(); ++j )
6366
{
64-
int jBound = qBound( 0, j, resolution.height() - 1 );
67+
int jBound = qBound( 0, j, jMax );
6568
const float z = z0 + static_cast<float>( jBound ) * dz;
6669
const float v = static_cast<float>( jBound ) * dv;
6770

6871
// Iterate over x
6972
for ( int i = -1; i <= resolution.width(); ++i )
7073
{
71-
int iBound = qBound( 0, i, resolution.width() - 1 );
74+
int iBound = qBound( 0, i, iMax );
7275
const float x = x0 + static_cast<float>( iBound ) * dx;
7376
const float u = static_cast<float>( iBound ) * du;
7477

@@ -83,18 +86,49 @@ static QByteArray createPlaneVertexData( int res, float skirtHeight, const QByte
8386

8487
// position
8588
*fptr++ = x;
86-
*fptr++ = height;
89+
*fptr++ = height / side * vertScale;
8790
*fptr++ = z;
8891

8992
// texture coordinates
9093
*fptr++ = u;
9194
*fptr++ = v;
9295

93-
// TODO: compute correct normals based on neighboring pixels
94-
// normal
95-
*fptr++ = 0.0f;
96-
*fptr++ = 1.0f;
97-
*fptr++ = 0.0f;
96+
// calculate normal coordinates
97+
#define zAt( ii, jj ) zData[ jj * resolution.width() + ii ] * vertScale
98+
float zi0 = zAt( qBound( 0, i - 1, iMax ), jBound );
99+
float zi1 = zAt( qBound( 0, i + 1, iMax ), jBound );
100+
float zj0 = zAt( iBound, qBound( 0, j - 1, jMax ) );
101+
float zj1 = zAt( iBound, qBound( 0, j + 1, jMax ) );
102+
103+
QVector3D n;
104+
if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
105+
n = QVector3D( 0, 1, 0 );
106+
else
107+
{
108+
float di, dj;
109+
float zij = height * vertScale;
110+
111+
if ( i == 0 )
112+
di = 2 * ( zij - zi1 );
113+
else if ( i == iMax )
114+
di = 2 * ( zi0 - zij );
115+
else
116+
di = zi0 - zi1;
117+
118+
if ( j == 0 )
119+
dj = 2 * ( zij - zj1 );
120+
else if ( j == jMax )
121+
dj = 2 * ( zj0 - zij );
122+
else
123+
dj = zj0 - zj1;
124+
125+
n = QVector3D( di, 2 * side / res, dj );
126+
n.normalize();
127+
}
128+
129+
*fptr++ = n.x();
130+
*fptr++ = n.y();
131+
*fptr++ = n.z();
98132
}
99133
}
100134

@@ -176,22 +210,26 @@ static QByteArray createPlaneIndexData( int res, const QByteArray &heightMap )
176210
class PlaneVertexBufferFunctor : public QBufferDataGenerator
177211
{
178212
public:
179-
explicit PlaneVertexBufferFunctor( int resolution, float skirtHeight, const QByteArray &heightMap )
213+
explicit PlaneVertexBufferFunctor( int resolution, float side, float vertScale, float skirtHeight, const QByteArray &heightMap )
180214
: mResolution( resolution )
215+
, mSide( side )
216+
, mVertScale( vertScale )
181217
, mSkirtHeight( skirtHeight )
182218
, mHeightMap( heightMap )
183219
{}
184220

185221
QByteArray operator()() final
186222
{
187-
return createPlaneVertexData( mResolution, mSkirtHeight, mHeightMap );
223+
return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
188224
}
189225

190226
bool operator ==( const QBufferDataGenerator &other ) const final
191227
{
192228
const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
193229
if ( otherFunctor != nullptr )
194230
return ( otherFunctor->mResolution == mResolution &&
231+
otherFunctor->mSide == mSide &&
232+
otherFunctor->mVertScale == mVertScale &&
195233
otherFunctor->mSkirtHeight == mSkirtHeight &&
196234
otherFunctor->mHeightMap == mHeightMap );
197235
return false;
@@ -201,6 +239,8 @@ class PlaneVertexBufferFunctor : public QBufferDataGenerator
201239

202240
private:
203241
int mResolution;
242+
float mSide;
243+
float mVertScale;
204244
float mSkirtHeight;
205245
QByteArray mHeightMap;
206246
};
@@ -239,9 +279,11 @@ class PlaneIndexBufferFunctor : public QBufferDataGenerator
239279
// ------------
240280

241281

242-
DemTerrainTileGeometry::DemTerrainTileGeometry( int resolution, float skirtHeight, const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
282+
DemTerrainTileGeometry::DemTerrainTileGeometry( int resolution, float side, float vertScale, float skirtHeight, const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
243283
: QGeometry( parent )
244284
, mResolution( resolution )
285+
, mSide( side )
286+
, mVertScale( vertScale )
245287
, mSkirtHeight( skirtHeight )
246288
, mHeightMap( heightMap )
247289
{
@@ -357,7 +399,7 @@ void DemTerrainTileGeometry::init()
357399

358400
// switched to setting data instead of just setting data generators because we also need the buffers
359401
// available for ray-mesh intersections and we can't access the private copy of data in Qt (if there is any)
360-
mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSkirtHeight, mHeightMap )() );
402+
mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
361403
mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
362404

363405
addAttribute( mPositionAttribute );

‎src/3d/terrain/qgsdemterraintilegeometry_p.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,16 @@ class DemTerrainTileGeometry : public Qt3DRender::QGeometry
5959
* Constructs a terrain tile geometry. Resolution is the number of vertices on one side of the tile,
6060
* heightMap is array of float values with one height value for each vertex
6161
*/
62-
explicit DemTerrainTileGeometry( int resolution, float skirtHeight, const QByteArray &heightMap, QNode *parent = nullptr );
62+
explicit DemTerrainTileGeometry( int resolution, float side, float vertScale, float skirtHeight, const QByteArray &heightMap, QNode *parent = nullptr );
6363

6464
bool rayIntersection( const QgsRayCastingUtils::Ray3D &ray, const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint );
6565

6666
private:
6767
void init();
6868

6969
int mResolution;
70+
float mSide;
71+
float mVertScale;
7072
float mSkirtHeight;
7173
QByteArray mHeightMap;
7274
Qt3DRender::QAttribute *mPositionAttribute = nullptr;

‎src/3d/terrain/qgsdemterraintileloader_p.cpp

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,20 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par
7676
return nullptr;
7777
}
7878

79+
const Qgs3DMapSettings &map = terrain()->map3D();
80+
QgsRectangle extent = map.terrainGenerator()->tilingScheme().tileToExtent( mNode->tileX(), mNode->tileY(), mNode->tileZ() ); //node->extent;
81+
double x0 = extent.xMinimum() - map.origin().x();
82+
double y0 = extent.yMinimum() - map.origin().y();
83+
double side = extent.width();
84+
double half = side / 2;
85+
86+
7987
QgsTerrainTileEntity *entity = new QgsTerrainTileEntity;
8088

8189
// create geometry renderer
8290

8391
Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer;
84-
mesh->setGeometry( new DemTerrainTileGeometry( mResolution, mSkirtHeight, mHeightMap, mesh ) );
92+
mesh->setGeometry( new DemTerrainTileGeometry( mResolution, side, map.terrainVerticalScale(), mSkirtHeight, mHeightMap, mesh ) );
8593
entity->addComponent( mesh ); // takes ownership if the component has no parent
8694

8795
// create material
@@ -94,14 +102,7 @@ Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *par
94102
transform = new Qt3DCore::QTransform();
95103
entity->addComponent( transform );
96104

97-
const Qgs3DMapSettings &map = terrain()->map3D();
98-
QgsRectangle extent = map.terrainGenerator()->tilingScheme().tileToExtent( mNode->tileX(), mNode->tileY(), mNode->tileZ() ); //node->extent;
99-
double x0 = extent.xMinimum() - map.origin().x();
100-
double y0 = extent.yMinimum() - map.origin().y();
101-
double side = extent.width();
102-
double half = side / 2;
103-
104-
transform->setScale3D( QVector3D( side, map.terrainVerticalScale(), side ) );
105+
transform->setScale( side );
105106
transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) );
106107

107108
mNode->setExactBbox( QgsAABB( x0, zMin * map.terrainVerticalScale(), -y0, x0 + side, zMax * map.terrainVerticalScale(), -( y0 + side ) ) );

0 commit comments

Comments
 (0)