1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "graphobjects/qssgrendermodel_p.h"
5#include "qssgdebugdrawsystem_p.h"
6
7#include "qssgrendermesh_p.h"
8#include "resourcemanager/qssgrenderbuffermanager_p.h"
9#include "rendererimpl/qssgrenderableobjects_p.h"
10
11QT_BEGIN_NAMESPACE
12
13QSSGDebugDrawSystem::QSSGDebugDrawSystem()
14{
15
16}
17
18QSSGDebugDrawSystem::~QSSGDebugDrawSystem()
19{
20
21}
22
23bool QSSGDebugDrawSystem::hasContent() const
24{
25 return !m_lines.isEmpty() || !m_persistentLines.isEmpty() || !m_bounds.isEmpty() || !m_persistentBounds.isEmpty() || !m_persistentPoints.isEmpty() || !m_points.isEmpty();
26}
27
28void QSSGDebugDrawSystem::drawLine(const QVector3D &startPoint,
29 const QVector3D &endPoint,
30 const QColor &color,
31 bool isPersistent)
32{
33 LineData line = {.startPoint: startPoint, .endPoint: endPoint, .color: color};
34 if (isPersistent)
35 m_persistentLines.append(t: line);
36 else
37 m_lines.append(t: line);
38}
39
40void QSSGDebugDrawSystem::drawBounds(const QSSGBounds3 &bounds,
41 const QColor &color,
42 bool isPersistent)
43{
44 BoundsData bound = {.bounds: bounds, .color: color};
45 if (isPersistent)
46 m_persistentBounds.append(t: bound);
47 else
48 m_bounds.append(t: bound);
49}
50
51void QSSGDebugDrawSystem::drawPoint(const QVector3D &vertex, const QColor &color, bool isPersistent)
52{
53 VertexData point = {.position: vertex, .color: {color.redF(), color.greenF(), color.blueF()}};
54 if (isPersistent)
55 m_persistentPoints.append(t: point);
56 else
57 m_points.append(t: point);
58}
59
60
61void QSSGDebugDrawSystem::prepareGeometry(QSSGRhiContext *rhiCtx, QRhiResourceUpdateBatch *rub)
62{
63
64 QVector<VertexData> vertexData;
65 QVector<quint32> indexData;
66 QVector<VertexData> pointsData;
67 for (const auto &line : m_persistentLines)
68 generateLine(line, vertexArray&: vertexData, indexArray&: indexData);
69 for (const auto &line : m_lines)
70 generateLine(line, vertexArray&: vertexData, indexArray&: indexData);
71 for (const auto &bounds : m_persistentBounds)
72 generateBox(bounds, vertexArray&: vertexData, indexArray&: indexData);
73 for (const auto &bounds : m_bounds)
74 generateBox(bounds, vertexArray&: vertexData, indexArray&: indexData);
75 pointsData = m_persistentPoints + m_points;
76
77 if (!vertexData.isEmpty()) {
78 // Lines
79 QByteArray vertexBufferData(reinterpret_cast<const char*>(vertexData.constData()), qsizetype(vertexData.count() * 6 * sizeof(float)));
80 QByteArray indexBufferData(reinterpret_cast<const char*>(indexData.constData()), qsizetype(indexData.count() * sizeof(quint32)));
81
82 if (m_lineVertexBuffer)
83 m_lineVertexBuffer.reset();
84 if (m_lineIndexBuffer)
85 m_lineIndexBuffer.reset();
86
87 m_lineVertexBuffer = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
88 args: QRhiBuffer::Immutable,
89 args: QRhiBuffer::VertexBuffer,
90 args: quint32(6 * sizeof(float)),
91 args: 6 * sizeof(float) * vertexData.count());
92 m_lineVertexBuffer->buffer()->setName(QByteArrayLiteral("debug lines vertex buffer"));
93 rub->uploadStaticBuffer(buf: m_lineVertexBuffer->buffer(), data: vertexBufferData.constData());
94
95 m_lineIndexBuffer = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
96 args: QRhiBuffer::Immutable,
97 args: QRhiBuffer::IndexBuffer,
98 args: 0,
99 args: indexBufferData.size(),
100 args: QRhiCommandBuffer::IndexUInt32);
101 m_lineIndexBuffer->buffer()->setName(QByteArrayLiteral("debug lines index buffer"));
102 rub->uploadStaticBuffer(buf: m_lineIndexBuffer->buffer(), data: indexBufferData.constData());
103
104 m_indexSize = indexData.count();
105 }
106
107 if (!pointsData.isEmpty()) {
108 // Points
109 QByteArray vertexBufferData(reinterpret_cast<const char*>(pointsData.constData()), qsizetype(pointsData.count() * 6 * sizeof(float)));
110
111 if (m_pointVertexBuffer)
112 m_pointVertexBuffer.reset();
113
114 m_pointVertexBuffer = std::make_shared<QSSGRhiBuffer>(args&: *rhiCtx,
115 args: QRhiBuffer::Immutable,
116 args: QRhiBuffer::VertexBuffer,
117 args: quint32(6 * sizeof(float)),
118 args: vertexBufferData.size());
119 m_pointVertexBuffer->buffer()->setName(QByteArrayLiteral("debug points vertex buffer"));
120 rub->uploadStaticBuffer(buf: m_pointVertexBuffer->buffer(), data: vertexBufferData.constData());
121 m_pointsSize = pointsData.count();
122 }
123}
124
125void QSSGDebugDrawSystem::recordRenderDebugObjects(QSSGRhiContext *rhiCtx,
126 QSSGRhiGraphicsPipelineState *ps,
127 QRhiShaderResourceBindings *srb,
128 QRhiRenderPassDescriptor *rpDesc)
129{
130 auto &ia = QSSGRhiInputAssemblerStatePrivate::get(ps&: *ps);
131 ia.inputLayout.setAttributes({
132 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
133 { 0, 1, QRhiVertexInputAttribute::Float3, 3 * sizeof(float) }
134 });
135 ia.inputs << QSSGRhiInputAssemblerState::PositionSemantic
136 << QSSGRhiInputAssemblerState::ColorSemantic;
137 ia.inputLayout.setBindings({6 * sizeof(float)});
138 ia.topology = QRhiGraphicsPipeline::Lines;
139 ps->flags |= QSSGRhiGraphicsPipelineState::Flag::DepthWriteEnabled;
140 ps->flags |= QSSGRhiGraphicsPipelineState::Flag::DepthTestEnabled;
141 ps->cullMode = QRhiGraphicsPipeline::None;
142
143 QSSGRhiContextPrivate *rhiCtxD = QSSGRhiContextPrivate::get(q: rhiCtx);
144 QRhiCommandBuffer *cb = rhiCtx->commandBuffer();
145 if (m_indexSize > 0) {
146 auto graphicsPipeline = rhiCtxD->pipeline(ps: *ps, rpDesc, srb);
147 cb->setGraphicsPipeline(graphicsPipeline);
148 cb->setShaderResources(srb);
149 cb->setViewport(ps->viewport);
150
151 // Lines
152 QRhiCommandBuffer::VertexInput vb(m_lineVertexBuffer->buffer(), 0);
153 cb->setVertexInput(startBinding: 0, bindingCount: 1, bindings: &vb, indexBuf: m_lineIndexBuffer->buffer(), indexOffset: 0, indexFormat: m_lineIndexBuffer->indexFormat());
154 cb->drawIndexed(indexCount: m_indexSize);
155 }
156
157 // Points
158 if (m_pointsSize > 0) {
159 ia.topology = QRhiGraphicsPipeline::Points;
160 auto graphicsPipeline = rhiCtxD->pipeline(ps: *ps, rpDesc, srb);
161 cb->setGraphicsPipeline(graphicsPipeline);
162 cb->setShaderResources(srb);
163 cb->setViewport(ps->viewport);
164
165 QRhiCommandBuffer::VertexInput vb(m_pointVertexBuffer->buffer(), 0);
166 cb->setVertexInput(startBinding: 0, bindingCount: 1, bindings: &vb);
167 cb->draw(vertexCount: m_pointsSize);
168 }
169
170 m_lines.clear();
171 m_bounds.clear();
172 m_points.clear();
173 m_indexSize = 0;
174 m_pointsSize = 0;
175}
176
177void QSSGDebugDrawSystem::setEnabled(bool v)
178{
179 modes = v ? (modes | ModeFlagT(Mode::Other)) : (modes & ~ModeFlagT(Mode::Other));
180}
181
182void QSSGDebugDrawSystem::generateLine(const LineData &line, QVector<VertexData> &vertexArray, QVector<quint32> &indexArray)
183{
184 const QVector3D color = {line.color.redF(), line.color.greenF(), line.color.blueF()};
185 indexArray.append(t: vertexArray.count());
186 vertexArray.append(t: {.position: line.startPoint, .color: color});
187 indexArray.append(t: vertexArray.count());
188 vertexArray.append(t: {.position: line.endPoint, .color: color});
189}
190
191void QSSGDebugDrawSystem::generateBox(const BoundsData &bounds, QVector<VertexData> &vertexArray, QVector<quint32> &indexArray)
192{
193 const QVector3D color = {bounds.color.redF(), bounds.color.greenF(), bounds.color.blueF()};
194
195 quint32 offset = vertexArray.count();
196 for (const QVector3D point : bounds.bounds.toQSSGBoxPoints())
197 vertexArray.append(t: {.position: point, .color: color});
198
199 indexArray.append(t: offset + 0);
200 indexArray.append(t: offset + 3);
201
202 indexArray.append(t: offset + 3);
203 indexArray.append(t: offset + 6);
204
205 indexArray.append(t: offset + 6);
206 indexArray.append(t: offset + 1);
207
208 indexArray.append(t: offset + 1);
209 indexArray.append(t: offset + 0);
210
211 indexArray.append(t: offset + 2);
212 indexArray.append(t: offset + 5);
213
214 indexArray.append(t: offset + 5);
215 indexArray.append(t: offset + 4);
216
217 indexArray.append(t: offset + 4);
218 indexArray.append(t: offset + 7);
219
220 indexArray.append(t: offset + 7);
221 indexArray.append(t: offset + 2);
222
223 indexArray.append(t: offset + 0);
224 indexArray.append(t: offset + 2);
225
226 indexArray.append(t: offset + 3);
227 indexArray.append(t: offset + 5);
228
229 indexArray.append(t: offset + 6);
230 indexArray.append(t: offset + 4);
231
232 indexArray.append(t: offset + 1);
233 indexArray.append(t: offset + 7);
234
235}
236
237QColor QSSGDebugDrawSystem::levelOfDetailColor(quint32 lod)
238{
239 static const QColor colors[] {
240 QColor(Qt::white),
241 QColor(Qt::red),
242 QColor(Qt::green),
243 QColor(Qt::blue),
244 QColor(Qt::yellow),
245 QColor(Qt::cyan),
246 QColor(Qt::magenta),
247 QColor(Qt::darkRed),
248 QColor(Qt::darkGreen),
249 QColor(Qt::darkBlue),
250 QColor(Qt::darkCyan),
251 QColor(Qt::darkMagenta),
252 QColor(Qt::darkYellow),
253 QColor(Qt::darkGray)
254 };
255
256 const size_t idx = qBound<size_t>(min: 0, val: lod, max: std::size(colors) - 1);
257 return colors[idx];
258}
259
260void QSSGDebugDrawSystem::debugNormals(QSSGBufferManager &bufferManager, const QSSGModelContext &theModelContext, const QSSGRenderSubset &theSubset, quint32 subsetLevelOfDetail, float lineLength)
261{
262 const auto &model = theModelContext.model;
263
264 QSSGMesh::Mesh mesh;
265 if (model.geometry)
266 mesh = bufferManager.loadMeshData(geometry: model.geometry);
267 else
268 mesh = bufferManager.loadMeshData(inSourcePath: model.meshPath);
269
270 if (!mesh.isValid())
271 return; // invalid mesh
272
273 QByteArray vertexData = mesh.vertexBuffer().data;
274 if (vertexData.isEmpty())
275 return; // no vertex dat
276 quint32 vertexStride = mesh.vertexBuffer().stride;
277 QByteArray indexData = mesh.indexBuffer().data;
278 if (indexData.isEmpty())
279 return; // no index data, not what we're after
280 if (mesh.indexBuffer().componentType != QSSGMesh::Mesh::ComponentType::UnsignedInt32)
281 return; // not uint3d, not what we're after either
282
283 quint32 positionOffset = UINT_MAX;
284 quint32 normalOffset = UINT_MAX;
285
286 for (const QSSGMesh::Mesh::VertexBufferEntry &vbe : mesh.vertexBuffer().entries) {
287 if (vbe.name == QSSGMesh::MeshInternal::getPositionAttrName()) {
288 positionOffset = vbe.offset;
289 if (vbe.componentType != QSSGMesh::Mesh::ComponentType::Float32 &&
290 vbe.componentCount != 3)
291 return; // not a vec3, some weird stuff
292 } else if (vbe.name == QSSGMesh::MeshInternal::getNormalAttrName()) {
293 normalOffset = vbe.offset;
294 if (vbe.componentType != QSSGMesh::Mesh::ComponentType::Float32 &&
295 vbe.componentCount != 3)
296 return; // not a vec3, really weird normals I guess
297 }
298 }
299
300 const auto globalTransform = model.globalTransform;
301 // Draw original vertex normals as blue lines
302 {
303 // Get Indexes
304 const quint32 *p = reinterpret_cast<const quint32 *>(indexData.constData());
305 const char *vp = vertexData.constData();
306 p += theSubset.offset;
307 for (uint i = 0; i < theSubset.count; ++i) {
308 const quint32 index = *(p + i);
309 const char * posPtr = vp + (index * vertexStride) + positionOffset;
310 const float *fPosPtr = reinterpret_cast<const float *>(posPtr);
311 QVector3D position(fPosPtr[0], fPosPtr[1], fPosPtr[2]);
312 const char * normalPtr = vp + (index * vertexStride) + normalOffset;
313 const float *fNormalPtr = reinterpret_cast<const float *>(normalPtr);
314 QVector3D normal(fNormalPtr[0], fNormalPtr[1], fNormalPtr[2]);
315 position = globalTransform.map(point: position);
316 normal = QSSGUtils::mat33::transform(m: theModelContext.normalMatrix, v: normal);
317 normal = normal.normalized();
318 drawLine(startPoint: position, endPoint: position + (normal * lineLength), color: QColor(Qt::blue));
319 }
320 }
321
322 // Draw lod vertex normals as red lines
323 if (subsetLevelOfDetail != 0) {
324 // Get Indexes
325 const quint32 *p = reinterpret_cast<const quint32 *>(indexData.constData());
326 const char *vp = vertexData.constData();
327 p += theSubset.lodOffset(lodLevel: subsetLevelOfDetail);
328 const quint32 indexCount = theSubset.lodCount(lodLevel: subsetLevelOfDetail);
329 for (uint i = 0; i < indexCount; ++i) {
330 const quint32 index = *(p + i);
331 const char * posPtr = vp + (index * vertexStride) + positionOffset;
332 const float *fPosPtr = reinterpret_cast<const float *>(posPtr);
333 QVector3D position(fPosPtr[0], fPosPtr[1], fPosPtr[2]);
334 const char * normalPtr = vp + (index * vertexStride) + normalOffset;
335 const float *fNormalPtr = reinterpret_cast<const float *>(normalPtr);
336 QVector3D normal(fNormalPtr[0], fNormalPtr[1], fNormalPtr[2]);
337 position = globalTransform.map(point: position);
338 normal = QSSGUtils::mat33::transform(m: theModelContext.normalMatrix, v: normal);
339 normal = normal.normalized();
340 drawLine(startPoint: position, endPoint: position + (normal * lineLength), color: QColor(Qt::red));
341 }
342 }
343}
344
345QT_END_NAMESPACE
346

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtquick3d/src/runtimerender/qssgdebugdrawsystem.cpp