Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
heightfieldgeometry.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5
53
55{
56 return m_heightMapSource;
57}
58
60{
61 if (m_heightMapSource == newSource)
62 return;
63 m_heightMapSource = newSource;
64
65 updateData();
66 update();
67
69}
70
72{
73 return m_smoothShading;
74}
75
77{
78 if (m_smoothShading == smooth)
79 return;
80 m_smoothShading = smooth;
81
82 updateData();
83 update();
84
86}
87
89{
90 return m_extents;
91}
92
94{
95 m_extentsSetExplicitly = true;
96 if (m_extents == newExtents)
97 return;
98 m_extents = newExtents;
99
100 updateData();
101 update();
103}
104
111
112void HeightFieldGeometry::updateData()
113{
114 const QQmlContext *context = qmlContext(this);
115
116 const auto resolvedUrl = context ? context->resolvedUrl(m_heightMapSource) : m_heightMapSource;
117 if (!resolvedUrl.isValid())
118 return;
119
120 clear();
121 const auto qmlSource = QQmlFile::urlToLocalFileOrQrc(resolvedUrl);
122
123 QImage heightMap(qmlSource);
124 int numRows = heightMap.height();
125 int numCols = heightMap.width();
126
127 if (numRows < 2 || numCols < 2)
128 return;
129
130 const int numVertices = numRows * numCols;
131
132 if (!m_extentsSetExplicitly) {
133 auto prevExt = m_extents;
134 if (numRows == numCols) {
135 m_extents = {100, 100, 100};
136 } else if (numRows < numCols) {
137 float f = float(numRows) / float(numCols);
138 m_extents = {100.f, 100.f, 100.f * f};
139 } else {
140 float f = float(numCols) / float(numRows);
141 m_extents = {100.f * f, 100.f, 100.f};
142 }
143 if (m_extents != prevExt) {
145 }
146 }
147
148 QVector<HeightFieldVertex> vertices;
149 vertices.reserve(numVertices);
150
151 const float rowF = m_extents.z() / (numRows - 1);
152 const float rowOffs = -m_extents.z() / 2;
153 const float colF = m_extents.x() / (numCols - 1);
154 const float colOffs = -m_extents.x() / 2;
155 for (int x = 0; x < numCols; x++) {
156 for (int y = 0; y < numRows; y++) {
157 float f = heightMap.pixelColor(x, y).valueF() - 0.5;
158 HeightFieldVertex vertex;
159 vertex.position = QVector3D(x * colF + colOffs, f * m_extents.y(), y * rowF + rowOffs);
160 vertex.normal = QVector3D(0, 0, 0);
161 vertex.uv = QVector2D(float(x) / (numCols - 1), 1.f - float(y) / (numRows - 1));
162 vertices.push_back(vertex);
163 }
164 }
165
166 QVector<quint32> indices;
167 for (int ix = 0; ix < numCols - 1; ++ix) {
168 for (int iy = 0; iy < numRows - 1; ++iy) {
169 const int idx = iy + ix * numRows;
170
171 const auto tri0 = std::array<int, 3> { idx + numRows + 1, idx + numRows, idx };
172 const auto tri1 = std::array<int, 3> { idx + 1, idx + numRows + 1, idx };
173
174 for (const auto [i0, i1, i2] : { tri0, tri1 }) {
175 indices.push_back(i0);
176 indices.push_back(i1);
177 indices.push_back(i2);
178
179 if (m_smoothShading) {
180 // Calculate face normal
181 const QVector3D e0 = vertices[i1].position - vertices[i0].position;
182 const QVector3D e1 = vertices[i2].position - vertices[i0].position;
183 QVector3D normal = QVector3D::crossProduct(e0, e1).normalized();
184
185 // Add normal to vertex, will normalize later
186 vertices[i0].normal += normal;
187 vertices[i1].normal += normal;
188 vertices[i2].normal += normal;
189 }
190 }
191 }
192 }
193
194 if (m_smoothShading) {
195 // Normalize
196 for (auto &vertex : vertices)
197 vertex.normal.normalize();
198 }
199
200 // Calculate bounds
201 QVector3D boundsMin = vertices[0].position;
202 QVector3D boundsMax = vertices[0].position;
203
204 for (const auto &vertex : vertices) {
205 const auto &p = vertex.position;
206 boundsMin = QVector3D(qMin(boundsMin.x(), p.x()), qMin(boundsMin.y(), p.y()), qMin(boundsMin.z(), p.z()));
207 boundsMax = QVector3D(qMax(boundsMax.x(), p.x()), qMax(boundsMax.y(), p.y()), qMax(boundsMax.z(), p.z()));
208 }
209
212
213 if (m_smoothShading)
215
217
219 QByteArray vertexBuffer(reinterpret_cast<char *>(vertices.data()), vertices.size() * sizeof(HeightFieldVertex));
220 setVertexData(vertexBuffer);
223
224 QByteArray indexBuffer(reinterpret_cast<char *>(indices.data()), indices.size() * sizeof(quint32));
225 setIndexData(indexBuffer);
226}
void setSource(const QUrl &newSource)
void setExtents(const QVector3D &newExtents)
HeightFieldGeometry()
\qmltype HeightFieldGeometry \inqmlmodule QtQuick3D.Helpers \inherits Geometry
void setSmoothShading(bool smooth)
\inmodule QtCore
Definition qbytearray.h:57
float valueF() const noexcept
Returns the value color component of this color.
Definition qcolor.cpp:1818
\inmodule QtGui
Definition qimage.h:37
int width() const
Returns the width of the image.
int height() const
Returns the height of the image.
QColor pixelColor(int x, int y) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.cpp:2709
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static QString urlToLocalFileOrQrc(const QString &)
If url is a local file returns a path suitable for passing to \l{QFile}.
Definition qqmlfile.cpp:742
void setPrimitiveType(PrimitiveType type)
Sets the primitive type used for rendering to type.
void setStride(int stride)
Sets the stride of the vertex buffer to stride, measured in bytes.
void addAttribute(Attribute::Semantic semantic, int offset, Attribute::ComponentType componentType)
Adds vertex attribute description.
void setVertexData(const QByteArray &data)
Sets the vertex buffer data.
int const QVector3D const QVector3D & boundsMax
Returns the maximum coordinate of the bounding volume.
int const QVector3D & boundsMin
Returns the minimum coordinate of the bounding volume.
void clear()
Resets the geometry to its initial state, clearing previously set vertex and index data as well as at...
void setBounds(const QVector3D &min, const QVector3D &max)
Sets the bounding volume of the geometry to the cube defined by the points min and max.
void setIndexData(const QByteArray &data)
Sets the index buffer to data.
\inmodule QtCore
Definition qurl.h:94
The QVector2D class represents a vector or vertex in 2D space.
Definition qvectornd.h:31
The QVector3D class represents a vector or vertex in 3D space.
Definition qvectornd.h:171
constexpr float y() const noexcept
Returns the y coordinate of this point.
Definition qvectornd.h:671
constexpr float x() const noexcept
Returns the x coordinate of this point.
Definition qvectornd.h:670
static constexpr QVector3D crossProduct(QVector3D v1, QVector3D v2) noexcept
Returns the cross-product of vectors v1 and v2, which is normal to the plane spanned by v1 and v2.
Definition qvectornd.h:775
constexpr float z() const noexcept
Returns the z coordinate of this point.
Definition qvectornd.h:672
static void * context
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat f
GLsizei GLenum const void * indices
GLint y
GLfloat GLfloat p
[1]
static void normalize(double &x, double &y)
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
static QUrl resolvedUrl(const QUrl &url, const QQmlRefPointer< QQmlContextData > &context)
#define emit
unsigned int quint32
Definition qtypes.h:50