seam fix attempt: fade anchor-edge alpha to 0 in mirrored mode, restore working 4-pass render loop

This commit is contained in:
pszsh 2026-02-27 02:21:26 -08:00
parent d78c85d4ad
commit 327e0d7dae
1 changed files with 65 additions and 63 deletions

View File

@ -384,49 +384,11 @@ void VisualizerWidget::render(QRhiCommandBuffer *cb) {
int w = width();
int h = height();
// Rebuild vertices when new data arrived or widget was resized
if (m_dataDirty || w != m_lastBuildW || h != m_lastBuildH) {
// Only rebuild vertices when new data has arrived
if (m_dataDirty) {
m_dataDirty = false;
m_lastBuildW = w;
m_lastBuildH = h;
if (m_mirrored) {
buildVertices(w * 0.55f, h / 2);
// Expand half-size vertices into all 4 quadrants (eliminates mirror seam)
{
int fillFloats = m_fillVertexCount * 6;
int lineFloats = m_lineVertexCount * 6;
float fw = (float)w, fh = (float)h;
auto expand = [&](const float *src, int nVerts, std::vector<float> &dst) {
for (int q = 0; q < 4; q++) {
bool fx = (q == 1 || q == 3);
bool fy = (q == 2 || q == 3);
for (int v = 0; v < nVerts; v++) {
int b = v * 6;
dst.push_back(fx ? fw - src[b] : src[b]);
dst.push_back(fy ? fh - src[b + 1] : src[b + 1]);
dst.push_back(src[b + 2]);
dst.push_back(src[b + 3]);
dst.push_back(src[b + 4]);
dst.push_back(src[b + 5]);
}
}
};
std::vector<float> expFill, expLine;
expFill.reserve(fillFloats * 4);
expLine.reserve(lineFloats * 4);
expand(m_vertices.data(), m_fillVertexCount, expFill);
expand(m_vertices.data() + fillFloats, m_lineVertexCount, expLine);
m_vertices.clear();
m_vertices.insert(m_vertices.end(), expFill.begin(), expFill.end());
m_vertices.insert(m_vertices.end(), expLine.begin(), expLine.end());
m_fillVertexCount *= 4;
m_lineVertexCount *= 4;
}
buildCepstrumVertices(w, h);
} else {
buildVertices(w, h);
@ -434,6 +396,8 @@ void VisualizerWidget::render(QRhiCommandBuffer *cb) {
}
}
int numPasses = m_mirrored ? 4 : 1;
// Prepare resource updates
QRhiResourceUpdateBatch *u = m_rhi->nextResourceUpdateBatch();
@ -454,13 +418,43 @@ void VisualizerWidget::render(QRhiCommandBuffer *cb) {
}
}
// Upload single full-screen ortho MVP (slot 0)
// Upload MVP matrices
QMatrix4x4 correction = m_rhi->clipSpaceCorrMatrix();
{
for (int i = 0; i < numPasses; i++) {
QMatrix4x4 proj;
proj.ortho(0, (float)w, (float)h, 0, -1, 1);
if (m_mirrored) {
switch (i) {
case 0: break;
case 1:
proj.translate(w, 0, 0);
proj.scale(-1, 1, 1);
break;
case 2:
proj.translate(0, h, 0);
proj.scale(1, -1, 1);
break;
case 3:
proj.translate(w, h, 0);
proj.scale(-1, -1, 1);
break;
}
}
QMatrix4x4 mvp = correction * proj;
u->updateDynamicBuffer(m_ubuf.get(), 0, 64, mvp.constData());
u->updateDynamicBuffer(m_ubuf.get(), i * m_ubufAlign, 64,
mvp.constData());
}
// Upload full-screen ortho MVP for cepstrum (slot 4)
if (m_mirrored && m_cepstrumVertexCount > 0) {
QMatrix4x4 cepProj;
cepProj.ortho(0, (float)w, (float)h, 0, -1, 1);
QMatrix4x4 cepMvp = correction * cepProj;
u->updateDynamicBuffer(m_ubuf.get(), 4 * m_ubufAlign, 64,
cepMvp.constData());
}
// Begin render pass
@ -469,26 +463,30 @@ void VisualizerWidget::render(QRhiCommandBuffer *cb) {
(float)outputSize.height()});
const QRhiCommandBuffer::VertexInput vbufBinding(m_vbuf.get(), 0);
QRhiCommandBuffer::DynamicOffset dynOfs(0, 0);
if (m_fillVertexCount > 0) {
cb->setGraphicsPipeline(m_fillPipeline.get());
cb->setShaderResources(m_srb.get(), 1, &dynOfs);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(m_fillVertexCount);
for (int i = 0; i < numPasses; i++) {
QRhiCommandBuffer::DynamicOffset dynOfs(0, quint32(i * m_ubufAlign));
if (m_fillVertexCount > 0) {
cb->setGraphicsPipeline(m_fillPipeline.get());
cb->setShaderResources(m_srb.get(), 1, &dynOfs);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(m_fillVertexCount);
}
if (m_lineVertexCount > 0) {
cb->setGraphicsPipeline(m_linePipeline.get());
cb->setShaderResources(m_srb.get(), 1, &dynOfs);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(m_lineVertexCount, 1, m_fillVertexCount, 0);
}
}
if (m_lineVertexCount > 0) {
cb->setGraphicsPipeline(m_linePipeline.get());
cb->setShaderResources(m_srb.get(), 1, &dynOfs);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(m_lineVertexCount, 1, m_fillVertexCount, 0);
}
// --- Cepstral Thread ---
// --- Cepstral Thread (single full-screen pass, after mirror loop) ---
if (m_mirrored && m_cepstrumVertexCount > 0) {
QRhiCommandBuffer::DynamicOffset cepOfs(0, quint32(4 * m_ubufAlign));
cb->setGraphicsPipeline(m_linePipeline.get());
cb->setShaderResources(m_srb.get(), 1, &dynOfs);
cb->setShaderResources(m_srb.get(), 1, &cepOfs);
cb->setVertexInput(0, 1, &vbufBinding);
cb->draw(m_cepstrumVertexCount, 1, m_fillVertexCount + m_lineVertexCount, 0);
}
@ -679,28 +677,32 @@ void VisualizerWidget::buildVertices(int w, int h) {
float fr = fillColor.redF(), fg = fillColor.greenF(),
fb = fillColor.blueF(), fa = fillColor.alphaF();
// In mirrored mode, fade anchor edge to transparent to hide mirror seam
float faAnchor = m_mirrored ? 0.0f : fa;
// Triangle 1
m_vertices.insert(m_vertices.end(),
{x1, anchorY, fr, fg, fb, fa, x1, y1, fr, fg, fb, fa,
{x1, anchorY, fr, fg, fb, faAnchor, x1, y1, fr, fg, fb, fa,
x2, y2, fr, fg, fb, fa});
// Triangle 2
m_vertices.insert(m_vertices.end(),
{x1, anchorY, fr, fg, fb, fa, x2, y2, fr, fg, fb, fa,
x2, anchorY, fr, fg, fb, fa});
{x1, anchorY, fr, fg, fb, faAnchor, x2, y2, fr, fg, fb, fa,
x2, anchorY, fr, fg, fb, faAnchor});
m_fillVertexCount += 6;
float lr = lineColor.redF(), lg = lineColor.greenF(),
lb = lineColor.blueF(), la = lineColor.alphaF();
float laAnchor = m_mirrored ? 0.0f : la;
// Left edge
lineVerts.insert(lineVerts.end(),
{x1, anchorY, lr, lg, lb, la, x1, y1, lr, lg, lb, la});
{x1, anchorY, lr, lg, lb, laAnchor, x1, y1, lr, lg, lb, la});
// Right edge (last bin only)
if (i + 2 == freqs.size()) {
lineVerts.insert(
lineVerts.end(),
{x2, anchorY, lr, lg, lb, la, x2, y2, lr, lg, lb, la});
{x2, anchorY, lr, lg, lb, laAnchor, x2, y2, lr, lg, lb, la});
}
}
}