Skip to content

Commit

Permalink
Mesh exploder
Browse files Browse the repository at this point in the history
New 'Exploded' visualisation mode in BufferViewer with new exploder controls
hidden when not in 'Exploded' mode.

Change 'solidShading' and 'solidShadeMode' to 'visualisation' and
'visualisationMode'.

Hide the 'highlightVerts' widget when using 'Exploded' vis for both
real-estate and practical implementation reasons.
  • Loading branch information
GertyP authored and baldurk committed Dec 9, 2023
1 parent da3e236 commit 442b48b
Show file tree
Hide file tree
Showing 23 changed files with 634 additions and 197 deletions.
2 changes: 1 addition & 1 deletion docs/getting_started/quick_start.rst
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ More details can be found on the :doc:`../window/mesh_viewer` page.

Mesh Viewer allows you to inspect the geometry data as it passes through the pipeline. Both raw data in a grid view and 3D inspection is possible. The tabs in the preview window allow you to choose at which part of the pipeline you'd like to visualise the data.

By default the preview shows a wireframe rendering of the mesh, but you can choose solid shading options. This can either be simple shading or use a secondary attribute as color. Right clicking on any column allows you to choose the secondary attribute for rendering.
By default the preview shows a wireframe rendering of the mesh, but you can choose different visualisations. This can either be simple shading, a vertex exploder utility, or using a secondary attribute as color. Right clicking on any column allows you to choose the secondary attribute for rendering.

You can also select which attribute is the position, in case either the auto-detection failed or you want to visualise another attribute like texture co-ordinates in 3D space.

Expand Down
Binary file added docs/imgs/Screenshots/ExploderBadShoes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/imgs/Screenshots/ExploderGoodShoes.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion docs/python_api/renderdoc/outputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Mesh View
.. autoclass:: MeshFormat
:members:

.. autoclass:: SolidShade
.. autoclass:: Visualisation
:members:

.. autoclass:: Camera
Expand Down
11 changes: 10 additions & 1 deletion docs/window/mesh_viewer.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,21 @@ Page up and Page down will move vertically 'up' and 'down' relative to the camer
Mesh Preview
------------

In the 3D Mesh preview, you have the option to display the mesh with some solid shading modes, not just as a wireframe mesh. When solid shading you can toggle the wireframe on and off.
In the 3D Mesh preview, you have the option to display the mesh with some colored visualisations, not just as a wireframe mesh. When using one of the visualisations, you can toggle the wireframe on and off.

* Solid Color simply displays a solid color for each triangle.
* Flat Shaded will perform basic flat lighting calculations based on triangle normals to give a better idea of the topology of the mesh.
* Secondary will display the selected secondary mesh element.
* Meshlet is only relevant when using mesh shaders, and will colourise each meshlet with a different colour.
* Exploded will display a shaded mesh where vertex colors are a function of the vertex index (SV_VertexID or gl_VertexID). This means adjacent primitives that do not share the exact same vertices can be more easily seen by a hard break in coloring. Additionally, a slider allows displacing vertices along an explosion direction by an amount based on the vertex index, which also helps better visualise shared or disjoint vertices and can also help in visualising other mesh problems (e.g. hidden or duplicate vertices/primitives).

.. figure:: ../imgs/Screenshots/ExploderBadShoes.png

Exploded: Visualising a mesh with no vertex sharing.

.. figure:: ../imgs/Screenshots/ExploderGoodShoes.png

Exploded: Visualising a mesh with widely shared vertices.

To select which element will be displayed as secondary, simply right click on the column you would like to use. This can be done on the input and output separately, and 4-component columns have the option to either show RGB as color, or alpha as grayscale.

Expand Down
42 changes: 42 additions & 0 deletions qrenderdoc/Styles/RDStyle/RDStyle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@

namespace Constants
{
static const int SliderHandleHalfWidth = 4;
static const int SliderGrooveHeight = 4;

static const int ButtonMargin = 6;
static const int ButtonBorder = 1;

Expand Down Expand Up @@ -470,6 +473,32 @@ QRect RDStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt,

return opt->rect;
}
else if(cc == QStyle::CC_Slider)
{
QRect ret = opt->rect;
ret.adjust(1, 1, -1, -1);
if(sc == QStyle::SC_SliderGroove)
{
int toGrooveHeightHalfReduction = (ret.height() - Constants::SliderGrooveHeight) / 2;
ret.adjust(Constants::SliderHandleHalfWidth, toGrooveHeightHalfReduction,
-Constants::SliderHandleHalfWidth, -toGrooveHeightHalfReduction);
}
else if(sc == QStyle::SC_SliderHandle)
{
const QAbstractSlider *slider = qobject_cast<const QAbstractSlider *>(widget);
int sliderMin = slider->minimum();
int sliderMax = slider->maximum();
int sliderPos = slider->sliderPosition();
qreal posUNorm = (qreal)(sliderPos - sliderMin) / (qreal)(sliderMax - sliderMin);
int grooveLeft = ret.left() + Constants::SliderHandleHalfWidth;
int grooveRight = ret.right() - Constants::SliderHandleHalfWidth;
int grooveWidth = grooveRight - grooveLeft;
int sliderX = (int)(posUNorm * (qreal)grooveWidth) + grooveLeft;
ret.setLeft(sliderX - Constants::SliderHandleHalfWidth);
ret.setRight(sliderX + Constants::SliderHandleHalfWidth);
}
return ret;
}
else if(cc == QStyle::CC_ComboBox)
{
QRect rect = opt->rect;
Expand Down Expand Up @@ -1118,6 +1147,19 @@ void RDStyle::drawComplexControl(ComplexControl control, const QStyleOptionCompl

return;
}
else if(control == QStyle::CC_Slider)
{
QRect grooveRect = subControlRect(control, opt, QStyle::SC_SliderGroove, widget);
p->drawLine(QLine(grooveRect.x(), grooveRect.y() + grooveRect.height() / 2, grooveRect.right(),
grooveRect.y() + grooveRect.height() / 2));

QRect handleRect = subControlRect(control, opt, QStyle::SC_SliderHandle, widget);
QBrush handleBrush = (m_Scheme == Light) ? opt->palette.brush(QPalette::Dark)
: opt->palette.brush(QPalette::Text);
p->fillRect(handleRect, handleBrush);

return;
}
else if(control == QStyle::CC_ComboBox)
{
const QStyleOptionComboBox *combo = qstyleoption_cast<const QStyleOptionComboBox *>(opt);
Expand Down
93 changes: 66 additions & 27 deletions qrenderdoc/Windows/BufferViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2402,6 +2402,7 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)
memset(&m_Config, 0, sizeof(m_Config));
m_Config.type = MeshDataStage::VSIn;
m_Config.wireframeDraw = true;
m_Config.exploderScale = 1.0f;

ui->outputTabs->setCurrentIndex(0);
m_CurStage = MeshDataStage::VSIn;
Expand Down Expand Up @@ -2537,10 +2538,11 @@ BufferViewer::BufferViewer(ICaptureContext &ctx, bool meshview, QWidget *parent)

configureDrawRange();

ui->solidShading->clear();
ui->solidShading->addItems({tr("None"), tr("Solid Colour"), tr("Flat Shaded"), tr("Secondary")});
ui->solidShading->adjustSize();
ui->solidShading->setCurrentIndex(0);
ui->visualisation->clear();
ui->visualisation->addItems(
{tr("None"), tr("Solid Colour"), tr("Flat Shaded"), tr("Secondary"), tr("Exploded")});
ui->visualisation->adjustSize();
ui->visualisation->setCurrentIndex(0);

ui->matrixType->addItems({tr("Perspective"), tr("Orthographic")});

Expand Down Expand Up @@ -2843,7 +2845,7 @@ void BufferViewer::SetupMeshView()
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setPosColumn(-1);
model->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
model->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary, false);

UI_ConfigureFormats();
on_resetCamera_clicked();
Expand All @@ -2863,8 +2865,8 @@ void BufferViewer::SetupMeshView()
QObject::connect(m_SelectSecondColumn, &QAction::triggered, [this]() {
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setSecondaryColumn(m_ContextColumn, m_Config.solidShadeMode == SolidShade::Secondary,
false);
model->setSecondaryColumn(m_ContextColumn,
m_Config.visualisationMode == Visualisation::Secondary, false);

UI_ConfigureFormats();
UpdateCurrentMeshConfig();
Expand All @@ -2873,8 +2875,8 @@ void BufferViewer::SetupMeshView()
QObject::connect(m_SelectSecondAlphaColumn, &QAction::triggered, [this]() {
BufferItemModel *model = (BufferItemModel *)m_CurView->model();

model->setSecondaryColumn(m_ContextColumn, m_Config.solidShadeMode == SolidShade::Secondary,
true);
model->setSecondaryColumn(m_ContextColumn,
m_Config.visualisationMode == Visualisation::Secondary, true);
UI_ConfigureFormats();
UpdateCurrentMeshConfig();
INVOKE_MEMFN(RT_UpdateAndDisplay);
Expand Down Expand Up @@ -3674,22 +3676,25 @@ void BufferViewer::OnEventChanged(uint32_t eventId)
// similarly for secondary columns
if(m_ModelIn->secondaryColumn() == -1 ||
bufdata->highlightNames[1] != bufdata->inConfig.columnName(m_ModelIn->secondaryColumn()))
m_ModelIn->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelIn->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

// and as above for VS Out / GS Out
if(m_ModelOut1->posColumn() == -1 ||
bufdata->highlightNames[2] != bufdata->out1Config.columnName(m_ModelOut1->posColumn()))
m_ModelOut1->setPosColumn(-1);
if(m_ModelOut1->secondaryColumn() == -1 ||
bufdata->highlightNames[3] != bufdata->out1Config.columnName(m_ModelOut1->secondaryColumn()))
m_ModelOut1->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelOut1->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

if(m_ModelOut2->posColumn() == -1 ||
bufdata->highlightNames[4] != bufdata->out2Config.columnName(m_ModelOut2->posColumn()))
m_ModelOut2->setPosColumn(-1);
if(m_ModelOut2->secondaryColumn() == -1 ||
bufdata->highlightNames[5] != bufdata->out2Config.columnName(m_ModelOut2->secondaryColumn()))
m_ModelOut2->setSecondaryColumn(-1, m_Config.solidShadeMode == SolidShade::Secondary, false);
m_ModelOut2->setSecondaryColumn(-1, m_Config.visualisationMode == Visualisation::Secondary,
false);

EnableCameraGuessControls();

Expand Down Expand Up @@ -5306,9 +5311,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(0, tr("Mesh Input"));
ui->outputTabs->setTabText(1, tr("Mesh Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) != tr("Meshlet"))
ui->solidShading->addItem(tr("Meshlet"));
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) != tr("Meshlet"))
ui->visualisation->addItem(tr("Meshlet"));
ui->visualisation->adjustSize();
}
else
{
Expand All @@ -5334,9 +5339,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(1, tr("VS Out"));
ui->outputTabs->setTabText(2, tr("GS/DS Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) == tr("Meshlet"))
ui->solidShading->removeItem(ui->solidShading->count() - 1);
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) == tr("Meshlet"))
ui->visualisation->removeItem(ui->visualisation->count() - 1);
ui->visualisation->adjustSize();
}
}
else
Expand All @@ -5363,9 +5368,9 @@ void BufferViewer::updateLabelsAndLayout()
ui->outputTabs->setTabText(1, tr("VS Out"));
ui->outputTabs->setTabText(2, tr("GS/DS Out"));

if(ui->solidShading->itemText(ui->solidShading->count() - 1) == tr("Meshlet"))
ui->solidShading->removeItem(ui->solidShading->count() - 1);
ui->solidShading->adjustSize();
if(ui->visualisation->itemText(ui->visualisation->count() - 1) == tr("Meshlet"))
ui->visualisation->removeItem(ui->visualisation->count() - 1);
ui->visualisation->adjustSize();
}
}
else
Expand Down Expand Up @@ -6678,7 +6683,7 @@ void BufferViewer::UpdateHighlightVerts()
{
m_Config.highlightVert = ~0U;

if(!ui->highlightVerts->isChecked())
if(ui->highlightVerts->isHidden() || !ui->highlightVerts->isChecked())
return;

RDTableView *table = currentTable();
Expand Down Expand Up @@ -6777,14 +6782,33 @@ void BufferViewer::on_highlightVerts_toggled(bool checked)
INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_vtxExploderSlider_valueChanged(int value)
{
m_Config.vtxExploderSliderSNorm = (float)value / 100.0f;

INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_exploderReset_clicked()
{
ui->vtxExploderSlider->setSliderPosition(0);
}

void BufferViewer::on_exploderScale_valueChanged(double value)
{
m_Config.exploderScale = (float)value;

INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_wireframeRender_toggled(bool checked)
{
m_Config.wireframeDraw = checked;

INVOKE_MEMFN(RT_UpdateAndDisplay);
}

void BufferViewer::on_solidShading_currentIndexChanged(int index)
void BufferViewer::on_visualisation_currentIndexChanged(int index)
{
ui->wireframeRender->setEnabled(index > 0);

Expand All @@ -6794,16 +6818,31 @@ void BufferViewer::on_solidShading_currentIndexChanged(int index)
m_Config.wireframeDraw = true;
}

m_Config.solidShadeMode = (SolidShade)qMax(0, index);
bool explodeHidden = (index != (int)Visualisation::Explode);
ui->vtxExploderLabel->setHidden(explodeHidden);
ui->vtxExploderSlider->setHidden(explodeHidden);
ui->exploderReset->setHidden(explodeHidden);
ui->exploderScaleLabel->setHidden(explodeHidden);
ui->exploderScale->setHidden(explodeHidden);
// Because the vertex/prim highlights draw from a new, temporary vertex buffer,
// those vertex IDs (which determine the explode displacement) won't necessarily
// match the original mesh's IDs and exploded vertices. Because of this, it seems
// cleanest to just avoid drawing the highlighted vert/prim with the explode
// visualisation (while also getting back a little room on the toolbar used by
// the extra exploder controls).
ui->highlightVerts->setHidden(!explodeHidden);
UpdateHighlightVerts();

m_Config.visualisationMode = (Visualisation)qMax(0, index);

m_ModelIn->setSecondaryColumn(m_ModelIn->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelIn->secondaryAlpha());
m_ModelOut1->setSecondaryColumn(m_ModelOut1->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelOut1->secondaryAlpha());
m_ModelOut2->setSecondaryColumn(m_ModelOut2->secondaryColumn(),
m_Config.solidShadeMode == SolidShade::Secondary,
m_Config.visualisationMode == Visualisation::Secondary,
m_ModelOut2->secondaryAlpha());

INVOKE_MEMFN(RT_UpdateAndDisplay);
Expand Down
5 changes: 4 additions & 1 deletion qrenderdoc/Windows/BufferViewer.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,11 @@ private slots:
void on_showPadding_toggled(bool checked);
void on_resourceDetails_clicked();
void on_highlightVerts_toggled(bool checked);
void on_vtxExploderSlider_valueChanged(int value);
void on_exploderReset_clicked();
void on_exploderScale_valueChanged(double value);
void on_wireframeRender_toggled(bool checked);
void on_solidShading_currentIndexChanged(int index);
void on_visualisation_currentIndexChanged(int index);
void on_drawRange_currentIndexChanged(int index);
void on_controlType_currentIndexChanged(int index);
void on_camSpeed_valueChanged(double value);
Expand Down
Loading

0 comments on commit 442b48b

Please sign in to comment.