145 srb.reset(rhi->newShaderResourceBindings());
150 QRhiShaderResourceBinding::uniformBufferWithDynamicOffset(0, QRhiShaderResourceBinding::VertexStage | QRhiShaderResourceBinding::FragmentStage,
uniformBuffer.get(),kUniformBlockSize)
156 auto getShader = [](
const QString &name) {
158 return f.open(QIODevice::ReadOnly) ? QShader::fromSerialized(f.readAll()) : QShader();
165 QString vert = (mode ==
Holographic || mode ==
XRay) ?
":/holographic.vert.qsb" :
166 (mode ==
Anatomical) ?
":/anatomical.vert.qsb" :
167 (mode ==
Dipole) ?
":/dipole.vert.qsb" :
168 (mode ==
ShowNormals) ?
":/shownormals.vert.qsb" :
":/standard.vert.qsb";
170 QString frag = (mode ==
Holographic || mode ==
XRay) ?
":/holographic.frag.qsb" :
171 (mode ==
Anatomical) ?
":/anatomical.frag.qsb" :
172 (mode ==
Dipole) ?
":/dipole.frag.qsb" :
173 (mode ==
ShowNormals) ?
":/shownormals.frag.qsb" :
":/standard.frag.qsb";
175 QShader vS = getShader(vert);
176 QShader fS = getShader(frag);
178 if (!vS.isValid() || !fS.isValid()) {
179 qWarning() <<
"BrainRenderer: Could not load shaders for mode" << mode << vert << frag;
184 auto pipeline = std::unique_ptr<QRhiGraphicsPipeline>(rhi->newGraphicsPipeline());
186 QRhiGraphicsPipeline::TargetBlend blend;
189 blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
190 blend.dstColor = QRhiGraphicsPipeline::One;
191 blend.srcAlpha = QRhiGraphicsPipeline::SrcAlpha;
192 blend.dstAlpha = QRhiGraphicsPipeline::One;
193 }
else if (mode ==
Dipole) {
195 blend.srcColor = QRhiGraphicsPipeline::SrcAlpha;
196 blend.dstColor = QRhiGraphicsPipeline::OneMinusSrcAlpha;
197 blend.srcAlpha = QRhiGraphicsPipeline::SrcAlpha;
198 blend.dstAlpha = QRhiGraphicsPipeline::OneMinusSrcAlpha;
201 auto setup = [&](QRhiGraphicsPipeline* p, QRhiGraphicsPipeline::CullMode cull) {
202 p->setShaderStages({{ QRhiShaderStage::Vertex, vS }, { QRhiShaderStage::Fragment, fS }});
204 QRhiVertexInputLayout il;
208 { 6 *
sizeof(float) },
209 { 21 *
sizeof(float), QRhiVertexInputBinding::PerInstance }
214 { 0, 0, QRhiVertexInputAttribute::Float3, 0 },
215 { 0, 1, QRhiVertexInputAttribute::Float3, 3 *
sizeof(float) },
219 { 1, 2, QRhiVertexInputAttribute::Float4, 0 },
220 { 1, 3, QRhiVertexInputAttribute::Float4, 4 *
sizeof(float) },
221 { 1, 4, QRhiVertexInputAttribute::Float4, 8 *
sizeof(float) },
222 { 1, 5, QRhiVertexInputAttribute::Float4, 12 *
sizeof(float) },
224 { 1, 6, QRhiVertexInputAttribute::Float4, 16 *
sizeof(float) },
226 { 1, 7, QRhiVertexInputAttribute::Float, 20 *
sizeof(float) }
229 il.setBindings({{ 32 }});
230 il.setAttributes({{ 0, 0, QRhiVertexInputAttribute::Float3, 0 },
231 { 0, 1, QRhiVertexInputAttribute::Float3, 12 },
232 { 0, 2, QRhiVertexInputAttribute::UNormByte4, 24 },
233 { 0, 3, QRhiVertexInputAttribute::UNormByte4, 28 }});
236 p->setVertexInputLayout(il);
237 p->setShaderResourceBindings(
srb.get());
238 p->setRenderPassDescriptor(rp);
239 p->setSampleCount(sampleCount);
240 p->setCullMode(cull);
242 p->setTargetBlends({blend});
243 p->setDepthTest(
true);
244 p->setDepthWrite(
false);
245 }
else if (mode ==
XRay) {
246 p->setTargetBlends({blend});
247 p->setDepthTest(
false);
248 p->setDepthWrite(
false);
249 }
else if (mode ==
Dipole) {
250 p->setTargetBlends({blend});
251 p->setCullMode(QRhiGraphicsPipeline::None);
252 p->setDepthTest(
true);
253 p->setDepthWrite(
false);
255 p->setDepthTest(
true);
256 p->setDepthWrite(
true);
258 p->setFlags(QRhiGraphicsPipeline::UsesScissor);
263 auto pipelineBack = std::unique_ptr<QRhiGraphicsPipeline>(rhi->newGraphicsPipeline());
264 setup(pipelineBack.get(), QRhiGraphicsPipeline::Front);
266 setup(pipeline.get(), QRhiGraphicsPipeline::Back);
269 setup(pipeline.get(), QRhiGraphicsPipeline::None);
307 if (!surface || !surface->
isVisible())
return;
310 if (d->pipelines.find(mode) == d->pipelines.end())
return;
312 auto *pipeline = d->pipelines[mode].get();
313 if (!pipeline)
return;
315 QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
319 int offset = d->currentUniformOffset;
320 d->currentUniformOffset += d->uniformBufferOffsetAlignment;
321 if (d->currentUniformOffset >= d->uniformBuffer->size()) {
322 qWarning(
"BrainRenderer: uniform buffer overflow (%d / %d bytes) — too many surfaces. Some draws will be skipped.",
323 d->currentUniformOffset, (
int)d->uniformBuffer->size());
327 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetMVP, 64, data.
mvp.constData());
328 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetCameraPos, 12, &data.
cameraPos);
330 float selected = surface->
isSelected() ? 1.0f : 0.0f;
331 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetSelected, 4, &selected);
333 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLightDir, 12, &data.
lightDir);
336 float tissueType =
static_cast<float>(surface->
tissueType());
337 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetTissueType, 4, &tissueType);
340 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLighting, 4, &lighting);
343 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetOverlayMode, 4, &overlayMode);
345 cb->resourceUpdate(u);
350 cb->setViewport(toViewport(data));
351 cb->setScissor(toScissor(data));
353 auto draw = [&](QRhiGraphicsPipeline *p) {
354 cb->setGraphicsPipeline(p);
356 const QRhiCommandBuffer::DynamicOffset srbOffset = { 0, uint32_t(offset) };
357 cb->setShaderResources(d->srb.get(), 1, &srbOffset);
358 const QRhiCommandBuffer::VertexInput vbuf(surface->
vertexBuffer(), 0);
359 cb->setVertexInput(0, 1, &vbuf, surface->
indexBuffer(), 0, QRhiCommandBuffer::IndexUInt32);
376 if (d->pipelines.find(
Dipole) == d->pipelines.end())
return;
378 auto *pipeline = d->pipelines[
Dipole].get();
379 if (!pipeline)
return;
381 QRhiResourceUpdateBatch *u = rhi->nextResourceUpdateBatch();
385 int offset = d->currentUniformOffset;
386 d->currentUniformOffset += d->uniformBufferOffsetAlignment;
387 if (d->currentUniformOffset >= d->uniformBuffer->size()) d->currentUniformOffset = 0;
389 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetMVP, 64, data.
mvp.constData());
390 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetCameraPos, 12, &data.
cameraPos);
391 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLightDir, 12, &data.
lightDir);
393 u->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLighting, 4, &lighting);
395 cb->resourceUpdate(u);
398 cb->setViewport(toViewport(data));
399 cb->setScissor(toScissor(data));
401 cb->setGraphicsPipeline(pipeline);
403 const QRhiCommandBuffer::DynamicOffset srbOffset = { 0, uint32_t(offset) };
404 cb->setShaderResources(d->srb.get(), 1, &srbOffset);
406 const QRhiCommandBuffer::VertexInput bindings[2] = {
407 QRhiCommandBuffer::VertexInput(dipoles->
vertexBuffer(), 0),
411 cb->setVertexInput(0, 2, bindings, dipoles->
indexBuffer(), 0, QRhiCommandBuffer::IndexUInt32);
422 if (d->pipelines.find(
Dipole) == d->pipelines.end())
return;
424 auto *pipeline = d->pipelines[
Dipole].get();
425 if (!pipeline)
return;
429 QRhiResourceUpdateBatch *uNodes = rhi->nextResourceUpdateBatch();
432 int offset = d->currentUniformOffset;
433 d->currentUniformOffset += d->uniformBufferOffsetAlignment;
434 if (d->currentUniformOffset >= d->uniformBuffer->size()) {
435 qWarning(
"BrainRenderer: uniform buffer overflow in renderNetwork (nodes)");
439 uNodes->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetMVP, 64, data.
mvp.constData());
440 uNodes->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetCameraPos, 12, &data.
cameraPos);
441 uNodes->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLightDir, 12, &data.
lightDir);
443 uNodes->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLighting, 4, &lighting);
445 cb->resourceUpdate(uNodes);
446 cb->setViewport(toViewport(data));
447 cb->setScissor(toScissor(data));
449 cb->setGraphicsPipeline(pipeline);
451 const QRhiCommandBuffer::DynamicOffset srbOffset = { 0, uint32_t(offset) };
452 cb->setShaderResources(d->srb.get(), 1, &srbOffset);
454 const QRhiCommandBuffer::VertexInput nodeBindings[2] = {
459 cb->setVertexInput(0, 2, nodeBindings, network->
nodeIndexBuffer(), 0, QRhiCommandBuffer::IndexUInt32);
465 QRhiResourceUpdateBatch *uEdges = rhi->nextResourceUpdateBatch();
468 int offset = d->currentUniformOffset;
469 d->currentUniformOffset += d->uniformBufferOffsetAlignment;
470 if (d->currentUniformOffset >= d->uniformBuffer->size()) {
471 qWarning(
"BrainRenderer: uniform buffer overflow in renderNetwork (edges)");
475 uEdges->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetMVP, 64, data.
mvp.constData());
476 uEdges->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetCameraPos, 12, &data.
cameraPos);
477 uEdges->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLightDir, 12, &data.
lightDir);
479 uEdges->updateDynamicBuffer(d->uniformBuffer.get(), offset + kOffsetLighting, 4, &lighting);
481 cb->resourceUpdate(uEdges);
482 cb->setViewport(toViewport(data));
483 cb->setScissor(toScissor(data));
485 cb->setGraphicsPipeline(pipeline);
487 const QRhiCommandBuffer::DynamicOffset srbOffset = { 0, uint32_t(offset) };
488 cb->setShaderResources(d->srb.get(), 1, &srbOffset);
490 const QRhiCommandBuffer::VertexInput edgeBindings[2] = {
495 cb->setVertexInput(0, 2, edgeBindings, network->
edgeIndexBuffer(), 0, QRhiCommandBuffer::IndexUInt32);