72 : m_bbMin(std::numeric_limits<float>::max(),
73 std::numeric_limits<float>::max(),
74 std::numeric_limits<float>::max())
75 , m_bbMax(std::numeric_limits<float>::lowest(),
76 std::numeric_limits<float>::lowest(),
77 std::numeric_limits<float>::lowest())
116 const QColor& minColor,
117 const QColor& maxColor)
119 if (values.isEmpty())
123 float minVal = std::numeric_limits<float>::max();
124 float maxVal = std::numeric_limits<float>::lowest();
125 for (
auto it = values.cbegin(); it != values.cend(); ++it) {
126 if (it.value() < minVal) minVal = it.value();
127 if (it.value() > maxVal) maxVal = it.value();
131 for (
auto& shaft : m_shafts) {
132 for (
auto& contact : shaft.contacts) {
133 auto it = values.find(contact.name);
134 if (it != values.end()) {
135 contact.value = it.value();
136 contact.color = interpolateColor(it.value(), minVal, maxVal,
189 QVector<unsigned int>& indices,
190 int cylinderSides)
const
195 if (cylinderSides < 3)
198 for (
const auto& shaft : m_shafts) {
199 if (shaft.contacts.size() < 2)
202 const QVector3D& tipPos = shaft.contacts.first().position;
203 const QVector3D& tailPos = shaft.contacts.last().position;
204 const QVector3D axis = tailPos - tipPos;
205 const float length = axis.length();
209 const QVector3D axisNorm = axis.normalized();
213 if (qAbs(QVector3D::dotProduct(axisNorm, QVector3D(0, 1, 0))) < 0.99f)
214 perp = QVector3D::crossProduct(axisNorm, QVector3D(0, 1, 0)).normalized();
216 perp = QVector3D::crossProduct(axisNorm, QVector3D(1, 0, 0)).normalized();
218 const QVector3D biperp = QVector3D::crossProduct(axisNorm, perp).normalized();
220 const float r = shaft.shaftRadius;
221 const unsigned int baseIdx =
static_cast<unsigned int>(vertices.size() / 6);
224 for (
int ring = 0; ring < 2; ++ring) {
225 const QVector3D center = (ring == 0) ? tipPos : tailPos;
226 for (
int i = 0; i < cylinderSides; ++i) {
227 const float angle = 2.0f * float(
M_PI) * float(i) / float(cylinderSides);
228 const float cs = cosf(angle);
229 const float sn = sinf(angle);
231 const QVector3D normal = (perp * cs + biperp * sn).normalized();
232 const QVector3D pos = center + normal * r;
235 vertices.append(pos.x());
236 vertices.append(pos.y());
237 vertices.append(pos.z());
239 vertices.append(normal.x());
240 vertices.append(normal.y());
241 vertices.append(normal.z());
246 for (
int i = 0; i < cylinderSides; ++i) {
247 const unsigned int i0 = baseIdx +
static_cast<unsigned int>(i);
248 const unsigned int i1 = baseIdx +
static_cast<unsigned int>((i + 1) % cylinderSides);
249 const unsigned int i2 = i0 +
static_cast<unsigned int>(cylinderSides);
250 const unsigned int i3 = i1 +
static_cast<unsigned int>(cylinderSides);
253 indices.append(i0); indices.append(i2); indices.append(i1);
254 indices.append(i1); indices.append(i2); indices.append(i3);
259 const QVector3D normal = -axisNorm;
260 const unsigned int centerIdx =
static_cast<unsigned int>(vertices.size() / 6);
261 vertices.append(tipPos.x());
262 vertices.append(tipPos.y());
263 vertices.append(tipPos.z());
264 vertices.append(normal.x());
265 vertices.append(normal.y());
266 vertices.append(normal.z());
268 for (
int i = 0; i < cylinderSides; ++i) {
269 const unsigned int i0 = baseIdx +
static_cast<unsigned int>(i);
270 const unsigned int i1 = baseIdx +
static_cast<unsigned int>((i + 1) % cylinderSides);
271 indices.append(centerIdx); indices.append(i1); indices.append(i0);
277 const QVector3D normal = axisNorm;
278 const unsigned int centerIdx =
static_cast<unsigned int>(vertices.size() / 6);
279 vertices.append(tailPos.x());
280 vertices.append(tailPos.y());
281 vertices.append(tailPos.z());
282 vertices.append(normal.x());
283 vertices.append(normal.y());
284 vertices.append(normal.z());
286 const unsigned int ring1Base = baseIdx +
static_cast<unsigned int>(cylinderSides);
287 for (
int i = 0; i < cylinderSides; ++i) {
288 const unsigned int i0 = ring1Base +
static_cast<unsigned int>(i);
289 const unsigned int i1 = ring1Base +
static_cast<unsigned int>((i + 1) % cylinderSides);
290 indices.append(centerIdx); indices.append(i0); indices.append(i1);
300 instanceData.clear();
301 const int floatsPerInstance = 9;
304 for (
const auto& shaft : m_shafts) {
305 for (
const auto& contact : shaft.contacts) {
307 instanceData.append(contact.position.x());
308 instanceData.append(contact.position.y());
309 instanceData.append(contact.position.z());
311 instanceData.append(contact.radius);
313 instanceData.append(
static_cast<float>(contact.color.redF()));
314 instanceData.append(
static_cast<float>(contact.color.greenF()));
315 instanceData.append(
static_cast<float>(contact.color.blueF()));
316 instanceData.append(
static_cast<float>(contact.color.alphaF()));
318 instanceData.append(contact.selected ? 1.0f : 0.0f);
392 const bool needsCreate = !m_gpu->vertexBuffer || !m_gpu->indexBuffer || !m_gpu->instanceBuffer;
395 if (!needsCreate && !m_gpu->dirty) {
397 if (m_gpu->shaftIndexCount > 0) {
398 QVector<float> verts;
399 QVector<unsigned int> idx;
401 u->uploadStaticBuffer(m_gpu->vertexBuffer.get(), verts.constData());
402 u->uploadStaticBuffer(m_gpu->indexBuffer.get(), idx.constData());
404 if (m_gpu->instanceCount > 0) {
407 u->uploadStaticBuffer(m_gpu->instanceBuffer.get(), inst.constData());
412 if (!m_gpu->dirty && !needsCreate)
return;
416 QVector<float> shaftVerts;
417 QVector<unsigned int> shaftIdx;
420 QVector<float> instData;
423 m_gpu->shaftIndexCount =
static_cast<uint32_t
>(shaftIdx.size());
424 m_gpu->instanceCount =
static_cast<uint32_t
>(instData.size() / 9);
427 const quint32 vbufSize =
static_cast<quint32
>(shaftVerts.size() *
sizeof(
float));
429 if (!m_gpu->vertexBuffer) {
430 m_gpu->vertexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, vbufSize));
431 m_gpu->vertexBuffer->create();
433 u->uploadStaticBuffer(m_gpu->vertexBuffer.get(), shaftVerts.constData());
437 const quint32 ibufSize =
static_cast<quint32
>(shaftIdx.size() *
sizeof(
unsigned int));
439 if (!m_gpu->indexBuffer) {
440 m_gpu->indexBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::IndexBuffer, ibufSize));
441 m_gpu->indexBuffer->create();
443 u->uploadStaticBuffer(m_gpu->indexBuffer.get(), shaftIdx.constData());
447 const quint32 instBufSize =
static_cast<quint32
>(instData.size() *
sizeof(
float));
448 if (instBufSize > 0) {
449 if (!m_gpu->instanceBuffer) {
450 m_gpu->instanceBuffer.reset(rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, instBufSize));
451 m_gpu->instanceBuffer->create();
453 u->uploadStaticBuffer(m_gpu->instanceBuffer.get(), instData.constData());
456 m_gpu->dirty =
false;