18 #include <Qt3DRender/qattribute.h> 19 #include <Qt3DRender/qbuffer.h> 20 #include <Qt3DRender/qbufferdatagenerator.h> 30 static QByteArray createPlaneVertexData(
int res,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heights )
33 Q_ASSERT( heights.count() == res * res *
static_cast<int>(
sizeof( float ) ) );
35 const float *zData = (
const float * ) heights.constData();
36 const float *zBits = zData;
38 const int nVerts = ( res + 2 ) * ( res + 2 );
42 const quint32 elementSize = 3 + 2 + 3;
43 const quint32 stride = elementSize *
sizeof( float );
44 QByteArray bufferBytes;
45 bufferBytes.resize( stride * nVerts );
46 float *fptr =
reinterpret_cast<float *
>( bufferBytes.data() );
49 QSize resolution( res, res );
50 const float x0 = -w / 2.0f;
51 const float z0 = -h / 2.0f;
52 const float dx = w / ( resolution.width() - 1 );
53 const float dz = h / ( resolution.height() - 1 );
54 const float du = 1.0 / ( resolution.width() - 1 );
55 const float dv = 1.0 / ( resolution.height() - 1 );
59 const float noDataHeight = 0;
61 const int iMax = resolution.width() - 1;
62 const int jMax = resolution.height() - 1;
65 for (
int j = -1; j <= resolution.height(); ++j )
67 int jBound = qBound( 0, j, jMax );
68 const float z = z0 +
static_cast<float>( jBound ) * dz;
69 const float v =
static_cast<float>( jBound ) * dv;
72 for (
int i = -1; i <= resolution.width(); ++i )
74 int iBound = qBound( 0, i, iMax );
75 const float x = x0 +
static_cast<float>( iBound ) * dx;
76 const float u =
static_cast<float>( iBound ) * du;
79 if ( i == iBound && j == jBound )
82 height = zData[ jBound * resolution.width() + iBound ] - skirtHeight;
84 if ( std::isnan( height ) )
85 height = noDataHeight;
89 *fptr++ = height / side * vertScale;
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 ) );
104 if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
105 n = QVector3D( 0, 1, 0 );
109 float zij = height * vertScale;
112 di = 2 * ( zij - zi1 );
113 else if ( i == iMax )
114 di = 2 * ( zi0 - zij );
119 dj = 2 * ( zij - zj1 );
120 else if ( j == jMax )
121 dj = 2 * ( zj0 - zij );
125 n = QVector3D( di, 2 * side / res, dj );
138 inline int ijToHeightMapIndex(
int i,
int j,
int resX,
int resZ )
140 i = qBound( 1, i, resX ) - 1;
141 j = qBound( 1, j, resZ ) - 1;
146 static bool hasNoData(
int i,
int j,
const float *heightMap,
int resX,
int resZ )
148 return std::isnan( heightMap[ ijToHeightMapIndex( i, j, resX, resZ ) ] ) ||
149 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j, resX, resZ ) ] ) ||
150 std::isnan( heightMap[ ijToHeightMapIndex( i, j + 1, resX, resZ ) ] ) ||
151 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j + 1, resX, resZ ) ] );
154 static QByteArray createPlaneIndexData(
int res,
const QByteArray &heightMap )
156 QSize resolution( res, res );
157 int numVerticesX = resolution.width() + 2;
158 int numVerticesZ = resolution.height() + 2;
161 const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
162 const quint32 indices = 3 * faces;
163 Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
164 QByteArray indexBytes;
165 indexBytes.resize( indices *
sizeof( quint32 ) );
166 quint32 *indexPtr =
reinterpret_cast<quint32 *
>( indexBytes.data() );
168 const float *heightMapFloat =
reinterpret_cast<const float *
>( heightMap.constData() );
171 for (
int j = 0; j < numVerticesZ - 1; ++j )
173 const int rowStartIndex = j * numVerticesX;
174 const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
177 for (
int i = 0; i < numVerticesX - 1; ++i )
179 if ( hasNoData( i, j, heightMapFloat, res, res ) )
183 *indexPtr++ = rowStartIndex + i;
184 *indexPtr++ = rowStartIndex + i;
185 *indexPtr++ = rowStartIndex + i;
187 *indexPtr++ = rowStartIndex + i;
188 *indexPtr++ = rowStartIndex + i;
189 *indexPtr++ = rowStartIndex + i;
194 *indexPtr++ = rowStartIndex + i;
195 *indexPtr++ = nextRowStartIndex + i;
196 *indexPtr++ = rowStartIndex + i + 1;
198 *indexPtr++ = nextRowStartIndex + i;
199 *indexPtr++ = nextRowStartIndex + i + 1;
200 *indexPtr++ = rowStartIndex + i + 1;
210 class PlaneVertexBufferFunctor :
public QBufferDataGenerator
213 explicit PlaneVertexBufferFunctor(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap )
214 : mResolution( resolution )
216 , mVertScale( vertScale )
217 , mSkirtHeight( skirtHeight )
218 , mHeightMap( heightMap )
221 QByteArray operator()() final
223 return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
226 bool operator ==(
const QBufferDataGenerator &other )
const final 228 const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
229 if ( otherFunctor !=
nullptr )
230 return ( otherFunctor->mResolution == mResolution &&
231 otherFunctor->mSide == mSide &&
232 otherFunctor->mVertScale == mVertScale &&
233 otherFunctor->mSkirtHeight == mSkirtHeight &&
234 otherFunctor->mHeightMap == mHeightMap );
238 QT3D_FUNCTOR( PlaneVertexBufferFunctor )
245 QByteArray mHeightMap;
250 class PlaneIndexBufferFunctor :
public QBufferDataGenerator
253 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
254 : mResolution( resolution )
255 , mHeightMap( heightMap )
258 QByteArray operator()() final
260 return createPlaneIndexData( mResolution, mHeightMap );
263 bool operator ==(
const QBufferDataGenerator &other )
const final 265 const PlaneIndexBufferFunctor *otherFunctor = functor_cast<PlaneIndexBufferFunctor>( &other );
266 if ( otherFunctor !=
nullptr )
267 return ( otherFunctor->mResolution == mResolution );
271 QT3D_FUNCTOR( PlaneIndexBufferFunctor )
275 QByteArray mHeightMap;
282 DemTerrainTileGeometry::DemTerrainTileGeometry(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
283 : QGeometry( parent )
284 , mResolution( resolution )
286 , mVertScale( vertScale )
287 , mSkirtHeight( skirtHeight )
288 , mHeightMap( heightMap )
293 static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRayCastingUtils::Ray3D &r,
const QMatrix4x4 &worldTransform, QVector3D &intPt )
298 const float *vertices =
reinterpret_cast<const float *
>( vertexBuf.constData() );
299 const uint *indices =
reinterpret_cast<const uint *
>( indexBuf.constData() );
300 int vertexCnt = vertexBuf.count() /
sizeof( float );
301 int indexCnt = indexBuf.count() /
sizeof( uint );
302 Q_ASSERT( vertexCnt % 8 == 0 );
303 Q_ASSERT( indexCnt % 3 == 0 );
305 int triangleCount = indexCnt / 3;
307 QVector3D intersectionPt, minIntersectionPt;
309 float minDistance = -1;
311 for (
int i = 0; i < triangleCount; ++i )
313 int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
314 QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
315 QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
316 QVector3D
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
318 const QVector3D tA = worldTransform * a;
319 const QVector3D tB = worldTransform * b;
320 const QVector3D tC = worldTransform *
c;
324 if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) )
326 intersectionPt = r.point( t * r.distance() );
327 distance = r.projectedDistance( intersectionPt );
330 if ( minDistance == -1 || distance < minDistance )
332 minDistance = distance;
333 minIntersectionPt = intersectionPt;
338 if ( minDistance != -1 )
340 intPt = minIntersectionPt;
347 bool DemTerrainTileGeometry::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
349 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, worldTransform, intersectionPoint );
352 void DemTerrainTileGeometry::init()
354 mPositionAttribute =
new QAttribute(
this );
355 mNormalAttribute =
new QAttribute(
this );
356 mTexCoordAttribute =
new QAttribute(
this );
357 mIndexAttribute =
new QAttribute(
this );
358 mVertexBuffer =
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer,
this );
359 mIndexBuffer =
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer,
this );
361 int nVertsX = mResolution + 2;
362 int nVertsZ = mResolution + 2;
363 const int nVerts = nVertsX * nVertsZ;
364 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
365 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
367 mPositionAttribute->setName( QAttribute::defaultPositionAttributeName() );
368 mPositionAttribute->setVertexBaseType( QAttribute::Float );
369 mPositionAttribute->setVertexSize( 3 );
370 mPositionAttribute->setAttributeType( QAttribute::VertexAttribute );
371 mPositionAttribute->setBuffer( mVertexBuffer );
372 mPositionAttribute->setByteStride( stride );
373 mPositionAttribute->setCount( nVerts );
375 mTexCoordAttribute->setName( QAttribute::defaultTextureCoordinateAttributeName() );
376 mTexCoordAttribute->setVertexBaseType( QAttribute::Float );
377 mTexCoordAttribute->setVertexSize( 2 );
378 mTexCoordAttribute->setAttributeType( QAttribute::VertexAttribute );
379 mTexCoordAttribute->setBuffer( mVertexBuffer );
380 mTexCoordAttribute->setByteStride( stride );
381 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
382 mTexCoordAttribute->setCount( nVerts );
384 mNormalAttribute->setName( QAttribute::defaultNormalAttributeName() );
385 mNormalAttribute->setVertexBaseType( QAttribute::Float );
386 mNormalAttribute->setVertexSize( 3 );
387 mNormalAttribute->setAttributeType( QAttribute::VertexAttribute );
388 mNormalAttribute->setBuffer( mVertexBuffer );
389 mNormalAttribute->setByteStride( stride );
390 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
391 mNormalAttribute->setCount( nVerts );
393 mIndexAttribute->setAttributeType( QAttribute::IndexAttribute );
394 mIndexAttribute->setVertexBaseType( QAttribute::UnsignedInt );
395 mIndexAttribute->setBuffer( mIndexBuffer );
398 mIndexAttribute->setCount( faces * 3 );
402 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
403 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
405 addAttribute( mPositionAttribute );
406 addAttribute( mTexCoordAttribute );
407 addAttribute( mNormalAttribute );
408 addAttribute( mIndexAttribute );
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c