18 #include <Qt3DRender/qattribute.h> 19 #include <Qt3DRender/qbuffer.h> 20 #include <Qt3DRender/qbufferdatagenerator.h> 30 static QByteArray createPlaneVertexData(
int res,
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;
62 for (
int j = -1; j <= resolution.height(); ++j )
64 int jBound = qBound( 0, j, resolution.height() - 1 );
65 const float z = z0 +
static_cast<float>( jBound ) * dz;
66 const float v =
static_cast<float>( jBound ) * dv;
69 for (
int i = -1; i <= resolution.width(); ++i )
71 int iBound = qBound( 0, i, resolution.width() - 1 );
72 const float x = x0 +
static_cast<float>( iBound ) * dx;
73 const float u =
static_cast<float>( iBound ) * du;
76 if ( i == iBound && j == jBound )
79 height = zData[ jBound * resolution.width() + iBound ] - skirtHeight;
81 if ( std::isnan( height ) )
82 height = noDataHeight;
104 inline int ijToHeightMapIndex(
int i,
int j,
int resX,
int resZ )
106 i = qBound( 1, i, resX ) - 1;
107 j = qBound( 1, j, resZ ) - 1;
112 static bool hasNoData(
int i,
int j,
const float *heightMap,
int resX,
int resZ )
114 return std::isnan( heightMap[ ijToHeightMapIndex( i, j, resX, resZ ) ] ) ||
115 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j, resX, resZ ) ] ) ||
116 std::isnan( heightMap[ ijToHeightMapIndex( i, j + 1, resX, resZ ) ] ) ||
117 std::isnan( heightMap[ ijToHeightMapIndex( i + 1, j + 1, resX, resZ ) ] );
120 static QByteArray createPlaneIndexData(
int res,
const QByteArray &heightMap )
122 QSize resolution( res, res );
123 int numVerticesX = resolution.width() + 2;
124 int numVerticesZ = resolution.height() + 2;
127 const int faces = 2 * ( numVerticesX - 1 ) * ( numVerticesZ - 1 );
128 const quint32 indices = 3 * faces;
129 Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
130 QByteArray indexBytes;
131 indexBytes.resize( indices *
sizeof( quint32 ) );
132 quint32 *indexPtr =
reinterpret_cast<quint32 *
>( indexBytes.data() );
134 const float *heightMapFloat =
reinterpret_cast<const float *
>( heightMap.constData() );
137 for (
int j = 0; j < numVerticesZ - 1; ++j )
139 const int rowStartIndex = j * numVerticesX;
140 const int nextRowStartIndex = ( j + 1 ) * numVerticesX;
143 for (
int i = 0; i < numVerticesX - 1; ++i )
145 if ( hasNoData( i, j, heightMapFloat, res, res ) )
149 *indexPtr++ = rowStartIndex + i;
150 *indexPtr++ = rowStartIndex + i;
151 *indexPtr++ = rowStartIndex + i;
153 *indexPtr++ = rowStartIndex + i;
154 *indexPtr++ = rowStartIndex + i;
155 *indexPtr++ = rowStartIndex + i;
160 *indexPtr++ = rowStartIndex + i;
161 *indexPtr++ = nextRowStartIndex + i;
162 *indexPtr++ = rowStartIndex + i + 1;
164 *indexPtr++ = nextRowStartIndex + i;
165 *indexPtr++ = nextRowStartIndex + i + 1;
166 *indexPtr++ = rowStartIndex + i + 1;
176 class PlaneVertexBufferFunctor :
public QBufferDataGenerator
179 explicit PlaneVertexBufferFunctor(
int resolution,
float skirtHeight,
const QByteArray &heightMap )
180 : mResolution( resolution )
181 , mSkirtHeight( skirtHeight )
182 , mHeightMap( heightMap )
185 QByteArray operator()() final
187 return createPlaneVertexData( mResolution, mSkirtHeight, mHeightMap );
190 bool operator ==(
const QBufferDataGenerator &other )
const final 192 const PlaneVertexBufferFunctor *otherFunctor = functor_cast<PlaneVertexBufferFunctor>( &other );
193 if ( otherFunctor !=
nullptr )
194 return ( otherFunctor->mResolution == mResolution &&
195 otherFunctor->mSkirtHeight == mSkirtHeight &&
196 otherFunctor->mHeightMap == mHeightMap );
200 QT3D_FUNCTOR( PlaneVertexBufferFunctor )
205 QByteArray mHeightMap;
210 class PlaneIndexBufferFunctor : public QBufferDataGenerator
213 explicit PlaneIndexBufferFunctor(
int resolution,
const QByteArray &heightMap )
214 : mResolution( resolution )
215 , mHeightMap( heightMap )
218 QByteArray operator()() final
220 return createPlaneIndexData( mResolution, mHeightMap );
223 bool operator ==(
const QBufferDataGenerator &other )
const final 225 const PlaneIndexBufferFunctor *otherFunctor = functor_cast<PlaneIndexBufferFunctor>( &other );
226 if ( otherFunctor !=
nullptr )
227 return ( otherFunctor->mResolution == mResolution );
231 QT3D_FUNCTOR( PlaneIndexBufferFunctor )
235 QByteArray mHeightMap;
242 DemTerrainTileGeometry::DemTerrainTileGeometry(
int resolution,
float skirtHeight, const QByteArray &heightMap, DemTerrainTileGeometry::QNode *parent )
243 : QGeometry( parent )
244 , mResolution( resolution )
245 , mSkirtHeight( skirtHeight )
246 , mHeightMap( heightMap )
251 static bool intersectionDemTriangles(
const QByteArray &vertexBuf,
const QByteArray &indexBuf,
const QgsRayCastingUtils::Ray3D &r,
const QMatrix4x4 &worldTransform, QVector3D &intPt )
256 const float *vertices =
reinterpret_cast<const float *
>( vertexBuf.constData() );
257 const uint *indices =
reinterpret_cast<const uint *
>( indexBuf.constData() );
258 int vertexCnt = vertexBuf.count() /
sizeof( float );
259 int indexCnt = indexBuf.count() /
sizeof( uint );
260 Q_ASSERT( vertexCnt % 8 == 0 );
261 Q_ASSERT( indexCnt % 3 == 0 );
263 int triangleCount = indexCnt / 3;
265 QVector3D intersectionPt, minIntersectionPt;
267 float minDistance = -1;
269 for (
int i = 0; i < triangleCount; ++i )
271 int v0 = indices[i * 3], v1 = indices[i * 3 + 1], v2 = indices[i * 3 + 2];
272 QVector3D a( vertices[v0 * 8], vertices[v0 * 8 + 1], vertices[v0 * 8 + 2] );
273 QVector3D b( vertices[v1 * 8], vertices[v1 * 8 + 1], vertices[v1 * 8 + 2] );
274 QVector3D
c( vertices[v2 * 8], vertices[v2 * 8 + 1], vertices[v2 * 8 + 2] );
276 const QVector3D tA = worldTransform * a;
277 const QVector3D tB = worldTransform * b;
278 const QVector3D tC = worldTransform *
c;
282 if ( QgsRayCastingUtils::rayTriangleIntersection( r, tA, tB, tC, uvw, t ) )
284 intersectionPt = r.point( t * r.distance() );
285 distance = r.projectedDistance( intersectionPt );
288 if ( minDistance == -1 || distance < minDistance )
290 minDistance = distance;
291 minIntersectionPt = intersectionPt;
296 if ( minDistance != -1 )
298 intPt = minIntersectionPt;
305 bool DemTerrainTileGeometry::rayIntersection(
const QgsRayCastingUtils::Ray3D &ray,
const QMatrix4x4 &worldTransform, QVector3D &intersectionPoint )
307 return intersectionDemTriangles( mVertexBuffer->data(), mIndexBuffer->data(), ray, worldTransform, intersectionPoint );
310 void DemTerrainTileGeometry::init()
312 mPositionAttribute =
new QAttribute(
this );
313 mNormalAttribute =
new QAttribute(
this );
314 mTexCoordAttribute =
new QAttribute(
this );
315 mIndexAttribute =
new QAttribute(
this );
316 mVertexBuffer =
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer,
this );
317 mIndexBuffer =
new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer,
this );
319 int nVertsX = mResolution + 2;
320 int nVertsZ = mResolution + 2;
321 const int nVerts = nVertsX * nVertsZ;
322 const int stride = ( 3 + 2 + 3 ) *
sizeof(
float );
323 const int faces = 2 * ( nVertsX - 1 ) * ( nVertsZ - 1 );
325 mPositionAttribute->setName( QAttribute::defaultPositionAttributeName() );
326 mPositionAttribute->setVertexBaseType( QAttribute::Float );
327 mPositionAttribute->setVertexSize( 3 );
328 mPositionAttribute->setAttributeType( QAttribute::VertexAttribute );
329 mPositionAttribute->setBuffer( mVertexBuffer );
330 mPositionAttribute->setByteStride( stride );
331 mPositionAttribute->setCount( nVerts );
333 mTexCoordAttribute->setName( QAttribute::defaultTextureCoordinateAttributeName() );
334 mTexCoordAttribute->setVertexBaseType( QAttribute::Float );
335 mTexCoordAttribute->setVertexSize( 2 );
336 mTexCoordAttribute->setAttributeType( QAttribute::VertexAttribute );
337 mTexCoordAttribute->setBuffer( mVertexBuffer );
338 mTexCoordAttribute->setByteStride( stride );
339 mTexCoordAttribute->setByteOffset( 3 *
sizeof(
float ) );
340 mTexCoordAttribute->setCount( nVerts );
342 mNormalAttribute->setName( QAttribute::defaultNormalAttributeName() );
343 mNormalAttribute->setVertexBaseType( QAttribute::Float );
344 mNormalAttribute->setVertexSize( 3 );
345 mNormalAttribute->setAttributeType( QAttribute::VertexAttribute );
346 mNormalAttribute->setBuffer( mVertexBuffer );
347 mNormalAttribute->setByteStride( stride );
348 mNormalAttribute->setByteOffset( 5 *
sizeof(
float ) );
349 mNormalAttribute->setCount( nVerts );
351 mIndexAttribute->setAttributeType( QAttribute::IndexAttribute );
352 mIndexAttribute->setVertexBaseType( QAttribute::UnsignedInt );
353 mIndexAttribute->setBuffer( mIndexBuffer );
356 mIndexAttribute->setCount( faces * 3 );
360 mVertexBuffer->setData( PlaneVertexBufferFunctor( mResolution, mSkirtHeight, mHeightMap )() );
361 mIndexBuffer->setData( PlaneIndexBufferFunctor( mResolution, mHeightMap )() );
363 addAttribute( mPositionAttribute );
364 addAttribute( mTexCoordAttribute );
365 addAttribute( mNormalAttribute );
366 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