49, m_startColor(QColor(60, 120, 255))
50, m_endColor(QColor(255, 80, 40))
52, m_bGeometryDirty(true)
53, m_bInstancesDirty(false)
56 createSegmentGeometry();
69 if (vecPoints.size() < 2) {
74 m_vecPoints = vecPoints;
83 m_instanceData.clear();
85 m_bInstancesDirty =
false;
99 const QColor& endColor)
101 m_startColor = startColor;
102 m_endColor = endColor;
108void PolylineObject::createSegmentGeometry()
110 if (!m_vertexData.isEmpty()) {
117 const int iSegments = 8;
118 const float fHalfHeight = 0.5f;
120 std::vector<VertexData> vertices;
121 std::vector<quint32> indices;
123 for (
int i = 0; i < iSegments; ++i) {
124 const float fAngle = 2.0f *
static_cast<float>(
M_PI) *
static_cast<float>(i) /
static_cast<float>(iSegments);
125 const float x = std::cos(fAngle);
126 const float z = std::sin(fAngle);
128 QVector3D normal(x, 0.0f, z);
131 vertices.push_back({x, fHalfHeight, z, normal.x(), normal.y(), normal.z()});
132 vertices.push_back({x, -fHalfHeight, z, normal.x(), normal.y(), normal.z()});
135 for (
int i = 0; i < iSegments; ++i) {
136 const quint32 uTop =
static_cast<quint32
>(i * 2);
137 const quint32 uBottom = uTop + 1;
138 const quint32 uNextTop =
static_cast<quint32
>(((i + 1) % iSegments) * 2);
139 const quint32 uNextBottom = uNextTop + 1;
141 indices.push_back(uTop);
142 indices.push_back(uBottom);
143 indices.push_back(uNextTop);
145 indices.push_back(uNextTop);
146 indices.push_back(uBottom);
147 indices.push_back(uNextBottom);
150 m_vertexData = QByteArray(
reinterpret_cast<const char*
>(vertices.data()),
151 static_cast<qsizetype
>(vertices.size() *
sizeof(VertexData)));
152 m_indexData = QByteArray(
reinterpret_cast<const char*
>(indices.data()),
153 static_cast<qsizetype
>(indices.size() *
sizeof(quint32)));
154 m_iIndexCount =
static_cast<int>(indices.size());
155 m_bGeometryDirty =
true;
160void PolylineObject::buildInstances()
162 if (m_vecPoints.size() < 2) {
163 m_instanceData.clear();
164 m_iInstanceCount = 0;
168 const int iSegmentCount = m_vecPoints.size() - 1;
169 std::vector<InstanceData> instances;
170 instances.reserve(
static_cast<size_t>(iSegmentCount));
172 const float fLastStep =
static_cast<float>(iSegmentCount - 1);
174 for (
int i = 0; i < iSegmentCount; ++i) {
175 const Eigen::Vector3f& vecStart = m_vecPoints.at(i);
176 const Eigen::Vector3f& vecEnd = m_vecPoints.at(i + 1);
178 const QVector3D start(vecStart.x(), vecStart.y(), vecStart.z());
179 const QVector3D end(vecEnd.x(), vecEnd.y(), vecEnd.z());
181 const QVector3D direction = end - start;
182 const float fLength = direction.length();
194 constexpr float fMinSegmentLength = 1.0e-12f;
195 if (fLength < fMinSegmentLength) {
200 model.translate((start + end) * 0.5f);
201 model.rotate(QQuaternion::rotationTo(QVector3D(0.0f, 1.0f, 0.0f),
202 direction / fLength));
203 model.scale(m_fRadius, fLength, m_fRadius);
205 InstanceData instance{};
206 memcpy(instance.model, model.constData(), 16 *
sizeof(
float));
210 const float fRatio = (fLastStep > 0.0f) ? (
static_cast<float>(i) / fLastStep) : 0.0f;
211 instance.color[0] =
static_cast<float>(m_startColor.redF() + (m_endColor.redF() - m_startColor.redF()) * fRatio);
212 instance.color[1] =
static_cast<float>(m_startColor.greenF() + (m_endColor.greenF() - m_startColor.greenF()) * fRatio);
213 instance.color[2] =
static_cast<float>(m_startColor.blueF() + (m_endColor.blueF() - m_startColor.blueF()) * fRatio);
214 instance.color[3] = 1.0f;
215 instance.isSelected = 0.0f;
217 instances.push_back(instance);
220 m_instanceData = QByteArray(
reinterpret_cast<const char*
>(instances.data()),
221 static_cast<qsizetype
>(instances.size() *
sizeof(InstanceData)));
222 m_iInstanceCount =
static_cast<int>(instances.size());
223 m_bInstancesDirty = m_iInstanceCount > 0;
230 if (m_bGeometryDirty) {
231 if (!m_gpu->vertexBuffer) {
232 m_gpu->vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable,
233 QRhiBuffer::VertexBuffer,
234 m_vertexData.size()));
235 m_gpu->vertexBuffer->create();
237 if (!m_gpu->indexBuffer) {
238 m_gpu->indexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable,
239 QRhiBuffer::IndexBuffer,
240 m_indexData.size()));
241 m_gpu->indexBuffer->create();
244 u->uploadStaticBuffer(m_gpu->vertexBuffer.get(), m_vertexData.constData());
245 u->uploadStaticBuffer(m_gpu->indexBuffer.get(), m_indexData.constData());
246 m_bGeometryDirty =
false;
249 if (m_bInstancesDirty && m_iInstanceCount > 0) {
250 const int iRequiredSize = m_instanceData.size();
252 if (!m_gpu->instanceBuffer || m_gpu->instanceBuffer->size() <
static_cast<quint32
>(iRequiredSize)) {
253 m_gpu->instanceBuffer.reset(rhi->newBuffer(QRhiBuffer::Dynamic,
254 QRhiBuffer::VertexBuffer,
256 m_gpu->instanceBuffer->create();
259 u->updateDynamicBuffer(m_gpu->instanceBuffer.get(), 0, iRequiredSize, m_instanceData.constData());
260 m_bInstancesDirty =
false;
268 return m_gpu->vertexBuffer.get();
275 return m_gpu->indexBuffer.get();
282 return m_gpu->instanceBuffer.get();
PolylineObject class declaration.
3-D brain visualisation using the Qt RHI rendering backend.
std::unique_ptr< QRhiBuffer > indexBuffer
std::unique_ptr< QRhiBuffer > vertexBuffer
std::unique_ptr< QRhiBuffer > instanceBuffer
void updateBuffers(QRhi *rhi, QRhiResourceUpdateBatch *u)
QRhiBuffer * instanceBuffer() const
QRhiBuffer * indexBuffer() const
void setRadius(float fRadius)
void setGradient(const QColor &startColor, const QColor &endColor)
QRhiBuffer * vertexBuffer() const
void setPoints(const QVector< Eigen::Vector3f > &vecPoints)