20#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
21#include <Qt3DRender/QAttribute>
22#include <Qt3DRender/QBuffer>
23#include <Qt3DRender/QAbstractFunctor>
28#include <Qt3DCore/QAttribute>
29#include <Qt3DCore/QBuffer>
30#include <Qt3DCore/QAbstractFunctor>
44static QByteArray createPlaneVertexData(
int res,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heights )
47 Q_ASSERT( heights.count() == res * res *
static_cast<int>(
sizeof(
float ) ) );
49 const float *zData = (
const float * ) heights.constData();
50 const float *zBits = zData;
52 const int nVerts = ( res + 2 ) * ( res + 2 );
56 const quint32 elementSize = 3 + 2 + 3;
57 const quint32 stride = elementSize *
sizeof( float );
58 QByteArray bufferBytes;
59 bufferBytes.resize( stride * nVerts );
60 float *fptr =
reinterpret_cast<float *
>( bufferBytes.data() );
63 QSize resolution( res, res );
64 const float x0 = -w / 2.0f;
65 const float z0 = -h / 2.0f;
66 const float dx = w / ( resolution.width() - 1 );
67 const float dz = h / ( resolution.height() - 1 );
68 const float du = 1.0 / ( resolution.width() - 1 );
69 const float dv = 1.0 / ( resolution.height() - 1 );
73 const float noDataHeight = 0;
75 const int iMax = resolution.width() - 1;
76 const int jMax = resolution.height() - 1;
79 for (
int j = -1; j <= resolution.height(); ++j )
81 int jBound = std::clamp( j, 0, jMax );
82 const float z = z0 +
static_cast<float>( jBound ) * dz;
83 const float v =
static_cast<float>( jBound ) * dv;
86 for (
int i = -1; i <= resolution.width(); ++i )
88 int iBound = std::clamp( i, 0, iMax );
89 const float x = x0 +
static_cast<float>( iBound ) * dx;
90 const float u =
static_cast<float>( iBound ) * du;
93 if ( i == iBound && j == jBound )
96 height = zData[ jBound * resolution.width() + iBound ] - skirtHeight;
98 if ( std::isnan( height ) )
99 height = noDataHeight;
103 *fptr++ = height / side * vertScale;
111#define zAt( ii, jj ) zData[ jj * resolution.width() + ii ] * vertScale
112 float zi0 = zAt( std::clamp( i - 1, 0, iMax ), jBound );
113 float zi1 = zAt( std::clamp( i + 1, 0, iMax ), jBound );
114 float zj0 = zAt( iBound, std::clamp( j - 1, 0, jMax ) );
115 float zj1 = zAt( iBound, std::clamp( j + 1, 0, jMax ) );
118 if ( std::isnan( zi0 ) || std::isnan( zi1 ) || std::isnan( zj0 ) || std::isnan( zj1 ) )
119 n = QVector3D( 0, 1, 0 );
123 float zij = height * vertScale;
126 di = 2 * ( zij - zi1 );
127 else if ( i == iMax )
128 di = 2 * ( zi0 - zij );
133 dj = 2 * ( zij - zj1 );
134 else if ( j == jMax )
135 dj = 2 * ( zj0 - zij );
139 n = QVector3D( di, 2 * side / res, dj );
152inline int ijToHeightMapIndex(
int i,
int j,
int resX,
int resZ )
154 i = std::clamp( i, 1, resX ) - 1;
155 j = std::clamp( j, 1, resZ ) - 1;
159static bool hasNoData(
int i,
int j,
const float *heightMap,
int resX,
int resZ )
161 return std::isnan( heightMap[ ijToHeightMapIndex( i, j, resX, resZ ) ] ) ||
162 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j, resX, resZ ) ] ) ||
163 std::isnan( heightMap[ ijToHeightMapIndex( i, j + 1, resX, resZ ) ] ) ||
164 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j + 1, resX, resZ ) ] );
167static QByteArray createPlaneIndexData(
int res,
const QByteArray &heightMap )
169 QSize resolution( res, res );
170 int numVerticesX = resolution.width() + 2;
171 int numVerticesZ = resolution.height() + 2;
174 const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
175 const quint32 indices = 3 * faces;
176 Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
177 QByteArray indexBytes;
178 indexBytes.resize( indices *
sizeof( quint32 ) );
179 quint32 *indexPtr =
reinterpret_cast<quint32 *
>( indexBytes.data() );
181 const float *heightMapFloat =
reinterpret_cast<const float *
>( heightMap.constData() );
184 for (
int j = 0; j < numVerticesZ - 1; ++j )
186 const int rowStartIndex = j * numVerticesX;
187 const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
190 for (
int i = 0; i < numVerticesX - 1; ++i )
192 if ( hasNoData( i, j, heightMapFloat, res, res ) )
196 *indexPtr++ = rowStartIndex + i;
197 *indexPtr++ = rowStartIndex + i;
198 *indexPtr++ = rowStartIndex + i;
200 *indexPtr++ = rowStartIndex + i;
201 *indexPtr++ = rowStartIndex + i;
202 *indexPtr++ = rowStartIndex + i;
207 *indexPtr++ = rowStartIndex + i;
208 *indexPtr++ = nextRowStartIndex + i;
209 *indexPtr++ = rowStartIndex + i + 1;
211 *indexPtr++ = nextRowStartIndex + i;
212 *indexPtr++ = nextRowStartIndex + i + 1;
213 *indexPtr++ = rowStartIndex + i + 1;
227 explicit PlaneVertexBufferFunctor(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap )
228 : mResolution( resolution )
230 , mVertScale( vertScale )
231 , mSkirtHeight( skirtHeight )
232 , mHeightMap( heightMap )
235 QByteArray operator()()
237 return createPlaneVertexData( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap );
242 const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
243 if ( otherFunctor !=
nullptr )
244 return ( otherFunctor->mResolution == mResolution &&
245 otherFunctor->mSide == mSide &&
246 otherFunctor->mVertScale == mVertScale &&
247 otherFunctor->mSkirtHeight == mSkirtHeight &&
248 otherFunctor->mHeightMap == mHeightMap );
252 QT3D_FUNCTOR( PlaneVertexBufferFunctor )
259 QByteArray mHeightMap;
267 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
268 : mResolution( resolution )
269 , mHeightMap( heightMap )
272 QByteArray operator()()
274 return createPlaneIndexData( mResolution, mHeightMap );
279 const PlaneIndexBufferFunctor *otherFunctor = functor_cast<PlaneIndexBufferFunctor>( &other );
280 if ( otherFunctor !=
nullptr )
281 return ( otherFunctor->mResolution == mResolution );
285 QT3D_FUNCTOR( PlaneIndexBufferFunctor )
289 QByteArray mHeightMap;
297DemTerrainTileGeometry::DemTerrainTileGeometry(
int resolution,
float side,
float vertScale,
float skirtHeight,
const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
298 : QGeometry( parent )
299 , mResolution( resolution )
301 , mVertScale( vertScale )
302 , mSkirtHeight( skirtHeight )
303 , mHeightMap( heightMap )
308static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRayCastingUtils::Ray3D &r,
const QMatrix4x4 &worldTransform, QVector3D &intPt )
313 const float *vertices =
reinterpret_cast<const float *
>( vertexBuf.constData() );
314 const uint *indices =
reinterpret_cast<const uint *
>( indexBuf.constData() );
316 int vertexCnt = vertexBuf.count() /
sizeof( float );
317 Q_ASSERT( vertexCnt % 8 == 0 );
319 int indexCnt = indexBuf.count() /
sizeof( uint );
320 Q_ASSERT( indexCnt % 3 == 0 );
321 int triangleCount = indexCnt / 3;
323 QVector3D intersectionPt, minIntersectionPt;
325 float minDistance = -1;
327 for (
int i = 0; i < triangleCount; ++i )
329 int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
330 QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
331 QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
332 QVector3D
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
334 const QVector3D tA = worldTransform * a;
335 const QVector3D tB = worldTransform * b;
336 const QVector3D tC = worldTransform *
c;
340 if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) )
342 intersectionPt = r.point( t * r.distance() );
343 distance = r.projectedDistance( intersectionPt );
346 if ( minDistance == -1 || distance < minDistance )
348 minDistance = distance;
349 minIntersectionPt = intersectionPt;
354 if ( minDistance != -1 )
356 intPt = minIntersectionPt;
363bool DemTerrainTileGeometry::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
365 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, worldTransform, intersectionPoint );
368void DemTerrainTileGeometry::init()
377 int nVertsX = mResolution + 2;
378 int nVertsZ = mResolution + 2;
379 const int nVerts = nVertsX * nVertsZ;
380 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
381 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
383 mPositionAttribute->setName( Qt3DQAttribute::defaultPositionAttributeName() );
384 mPositionAttribute->setVertexBaseType( Qt3DQAttribute::Float );
385 mPositionAttribute->setVertexSize( 3 );
386 mPositionAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
387 mPositionAttribute->setBuffer( mVertexBuffer );
388 mPositionAttribute->setByteStride( stride );
389 mPositionAttribute->setCount( nVerts );
391 mTexCoordAttribute->setName( Qt3DQAttribute::defaultTextureCoordinateAttributeName() );
392 mTexCoordAttribute->setVertexBaseType( Qt3DQAttribute::Float );
393 mTexCoordAttribute->setVertexSize( 2 );
394 mTexCoordAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
395 mTexCoordAttribute->setBuffer( mVertexBuffer );
396 mTexCoordAttribute->setByteStride( stride );
397 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
398 mTexCoordAttribute->setCount( nVerts );
400 mNormalAttribute->setName( Qt3DQAttribute::defaultNormalAttributeName() );
401 mNormalAttribute->setVertexBaseType( Qt3DQAttribute::Float );
402 mNormalAttribute->setVertexSize( 3 );
403 mNormalAttribute->setAttributeType( Qt3DQAttribute::VertexAttribute );
404 mNormalAttribute->setBuffer( mVertexBuffer );
405 mNormalAttribute->setByteStride( stride );
406 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
407 mNormalAttribute->setCount( nVerts );
409 mIndexAttribute->setAttributeType( Qt3DQAttribute::IndexAttribute );
410 mIndexAttribute->setVertexBaseType( Qt3DQAttribute::UnsignedInt );
411 mIndexAttribute->setBuffer( mIndexBuffer );
414 mIndexAttribute->setCount( faces * 3 );
419 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSide, mVertScale, mSkirtHeight, mHeightMap )() );
420 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
422 addAttribute( mPositionAttribute );
423 addAttribute( mTexCoordAttribute );
424 addAttribute( mNormalAttribute );
425 addAttribute( mIndexAttribute );
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
#define Q_NOWARN_DEPRECATED_POP
#define Q_NOWARN_DEPRECATED_PUSH
Qt3DCore::QAbstractFunctor Qt3DQAbstractFunctor
Qt3DCore::QAttribute Qt3DQAttribute
Qt3DCore::QBuffer Qt3DQBuffer
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)