27
27
using namespace Qt3DRender ;
28
28
29
29
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 )
31
31
{
32
32
Q_ASSERT ( res >= 2 );
33
33
Q_ASSERT ( heights.count () == res * res * static_cast <int >( sizeof ( float ) ) );
@@ -58,17 +58,20 @@ static QByteArray createPlaneVertexData( int res, float skirtHeight, const QByte
58
58
// as we do not create valid triangles that would use such vertices
59
59
const float noDataHeight = 0 ;
60
60
61
+ const int iMax = resolution.width () - 1 ;
62
+ const int jMax = resolution.height () - 1 ;
63
+
61
64
// Iterate over z
62
65
for ( int j = -1 ; j <= resolution.height (); ++j )
63
66
{
64
- int jBound = qBound ( 0 , j, resolution. height () - 1 );
67
+ int jBound = qBound ( 0 , j, jMax );
65
68
const float z = z0 + static_cast <float >( jBound ) * dz;
66
69
const float v = static_cast <float >( jBound ) * dv;
67
70
68
71
// Iterate over x
69
72
for ( int i = -1 ; i <= resolution.width (); ++i )
70
73
{
71
- int iBound = qBound ( 0 , i, resolution. width () - 1 );
74
+ int iBound = qBound ( 0 , i, iMax );
72
75
const float x = x0 + static_cast <float >( iBound ) * dx;
73
76
const float u = static_cast <float >( iBound ) * du;
74
77
@@ -83,18 +86,49 @@ static QByteArray createPlaneVertexData( int res, float skirtHeight, const QByte
83
86
84
87
// position
85
88
*fptr++ = x;
86
- *fptr++ = height;
89
+ *fptr++ = height / side * vertScale ;
87
90
*fptr++ = z;
88
91
89
92
// texture coordinates
90
93
*fptr++ = u;
91
94
*fptr++ = v;
92
95
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 ();
98
132
}
99
133
}
100
134
@@ -176,22 +210,26 @@ static QByteArray createPlaneIndexData( int res, const QByteArray &heightMap )
176
210
class PlaneVertexBufferFunctor : public QBufferDataGenerator
177
211
{
178
212
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 )
180
214
: mResolution( resolution )
215
+ , mSide( side )
216
+ , mVertScale( vertScale )
181
217
, mSkirtHeight( skirtHeight )
182
218
, mHeightMap( heightMap )
183
219
{}
184
220
185
221
QByteArray operator ()() final
186
222
{
187
- return createPlaneVertexData ( mResolution , mSkirtHeight , mHeightMap );
223
+ return createPlaneVertexData ( mResolution , mSide , mVertScale , mSkirtHeight , mHeightMap );
188
224
}
189
225
190
226
bool operator ==( const QBufferDataGenerator &other ) const final
191
227
{
192
228
const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
193
229
if ( otherFunctor != nullptr )
194
230
return ( otherFunctor->mResolution == mResolution &&
231
+ otherFunctor->mSide == mSide &&
232
+ otherFunctor->mVertScale == mVertScale &&
195
233
otherFunctor->mSkirtHeight == mSkirtHeight &&
196
234
otherFunctor->mHeightMap == mHeightMap );
197
235
return false ;
@@ -201,6 +239,8 @@ class PlaneVertexBufferFunctor : public QBufferDataGenerator
201
239
202
240
private:
203
241
int mResolution ;
242
+ float mSide ;
243
+ float mVertScale ;
204
244
float mSkirtHeight ;
205
245
QByteArray mHeightMap ;
206
246
};
@@ -239,9 +279,11 @@ class PlaneIndexBufferFunctor : public QBufferDataGenerator
239
279
// ------------
240
280
241
281
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 )
243
283
: QGeometry( parent )
244
284
, mResolution( resolution )
285
+ , mSide( side )
286
+ , mVertScale( vertScale )
245
287
, mSkirtHeight( skirtHeight )
246
288
, mHeightMap( heightMap )
247
289
{
@@ -357,7 +399,7 @@ void DemTerrainTileGeometry::init()
357
399
358
400
// switched to setting data instead of just setting data generators because we also need the buffers
359
401
// 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 )() );
361
403
mIndexBuffer ->setData ( PlaneIndexBufferFunctor ( mResolution , mHeightMap )() );
362
404
363
405
addAttribute ( mPositionAttribute );
0 commit comments