Mac OSX QQuickFramebufferObject
I'm currently working on an issue where the axis look off (I'm not sure how to describe it), as well as some of the lines in a vtkChartXY
. I am working on incorporating VTK renderings into a Qt QQuick application, through the use of a QQuickFramebufferObject
. I found an example here and tried to use it: https://github.com/nicanor-romero/QtVtk . In summary, it uses a vtkExternalRenderWindow
to render to before filling out the FBO (I think).
This is what the chart looks like:
As you can see, the axis text looks a bit off and I can't figure out how to smooth anything (SetLineSmoothing
does nothing).
This is the main rendering header file:
class DepthChartView;
class DepthChartRenderer : public QObject, public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions
{
Q_OBJECT
public:
DepthChartRenderer();
virtual void synchronize(QQuickFramebufferObject * item);
virtual void render();
virtual void openGLInitState();
QOpenGLFramebufferObject * createFramebufferObject(const QSize & size);
private:
void initScene();
DepthChartView * m_vtkFboItem = nullptr;
uint m_realTime;
vtkSmartPointer<vtkExternalOpenGLRenderWindow> m_vtkRenderWindow;
vtkSmartPointer<vtkRenderer> m_renderer;
vtkSmartPointer<vtkGenericRenderWindowInteractor> m_vtkRenderWindowInteractor;
std::map<std::string, std::vector<uint>> m_bpdAnimationFrames;
std::map<std::string, std::vector<uint>> m_cpdAnimationFrames;
vtkSmartPointer<vtkTable> m_bpdTable;
std::vector<std::vector<vtkSmartPointer<vtkTable>>> m_cpdTables;
vtkSmartPointer<vtkChartXY> m_chart;
vtkSmartPointer<vtkContextView> m_view;
vtkPlot * m_bpdLine;
std::vector<std::vector<vtkPlot *>> m_cpdLines;
std::vector<uint> r = {255, 0, 0};
std::vector<uint> g = {0, 255, 0};
std::vector<uint> b = {0, 0, 255};
bool m_firstRender = true;
};
And this is the source for it:
DepthChartRenderer::DepthChartRenderer()
: m_realTime(0), m_bpdAnimationFrames(), m_cpdAnimationFrames(), m_bpdLine(0), m_cpdLines()
{
// Renderer
m_vtkRenderWindow = vtkSmartPointer<vtkExternalOpenGLRenderWindow>::New();
m_renderer = vtkSmartPointer<vtkRenderer>::New();
m_vtkRenderWindow->AddRenderer(m_renderer);
// Initialize the OpenGL context for the renderer
m_vtkRenderWindow->OpenGLInitContext();
update();
}
void DepthChartRenderer::synchronize(QQuickFramebufferObject * item)
{
// For the first synchronize
if (!m_vtkFboItem) {
m_vtkFboItem = static_cast<DepthChartView *>(item);
}
if (!m_vtkFboItem->isInitialized()) {
m_vtkFboItem->setVtkFboRenderer(this);
emit m_vtkFboItem->rendererInitialized();
}
int * rendererSize = m_vtkRenderWindow->GetSize();
if (m_vtkFboItem->width() != rendererSize[0] || m_vtkFboItem->height() != rendererSize[1]) {
m_vtkRenderWindow->SetSize(m_vtkFboItem->width(), m_vtkFboItem->height());
}
// Copy animation frames
for (auto entry : m_vtkFboItem->m_bpdAnimationFrames) {
m_bpdAnimationFrames[entry.first] = entry.second;
}
m_vtkFboItem->m_bpdAnimationFrames.clear();
for (auto entry : m_vtkFboItem->m_cpdAnimationFrames) {
m_cpdAnimationFrames[entry.first] = entry.second;
}
// Create the chart
if (!m_chart) {
// Add multiple line plots, setting the colors etc
m_chart = vtkSmartPointer<vtkChartXY>::New();
m_chart->GetAxis(vtkAxis::BOTTOM)->SetTitle("Depth");
m_chart->GetAxis(vtkAxis::LEFT)->SetTitle("#BT");
m_chart->GetAxis(vtkAxis::RIGHT)->SetTitle("#Calls");
}
// Create a table with some points in it
if (!m_bpdTable) {
m_bpdTable = vtkSmartPointer<vtkTable>::New();
vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
arrX->SetName("X Axis");
m_bpdTable->AddColumn(arrX);
// Fill in the table with some example values
int numPoints = 1;
int numRows = 1;
if (m_vtkFboItem != nullptr && m_vtkFboItem->model() != nullptr) {
numRows = m_vtkFboItem->model()->bpdFrameCount();
numPoints = m_vtkFboItem->model()->bpdData(0).second.size();
}
// Add a column for each DepthChart Frame
for (int i = 0; i < numRows; ++i) {
vtkSmartPointer<vtkFloatArray> arrC = vtkSmartPointer<vtkFloatArray>::New();
auto name = "DepthChart-BpD-" + std::to_string(i);
arrC->SetName(name.c_str());
m_bpdTable->AddColumn(arrC);
}
m_bpdTable->SetNumberOfRows(numPoints);
// Fill out x-axis data
for (int j = 0; j < numPoints; ++j) {
m_bpdTable->SetValue(j, 0, j);
}
// Fill out entire table with all DepthChart data
std::vector<uint> data = {0};
for (int i = 0; i < numRows; ++i) {
data = m_vtkFboItem->model()->bpdData(i).second;
for (int j = 0; j < numPoints; ++j) {
m_bpdTable->SetValue(j, i + 1, data[j]);
}
}
}
if (m_cpdTables.size() == 0) {
int numPoints = 1;
int numCols = 1;
if (m_vtkFboItem != nullptr && m_vtkFboItem->model() != nullptr) {
numCols = m_vtkFboItem->model()->cpdFrameCount();
numPoints = m_vtkFboItem->model()->cpdData(0).second[0][0].size();
}
// Initialize tables with x-axis
for (uint lineIndex = 0; lineIndex < m_vtkFboItem->model()->cpdLineLabels().size(); ++lineIndex) {
std::vector<vtkSmartPointer<vtkTable>> algoTables;
for (uint algoIndex = 0; algoIndex < m_vtkFboItem->model()->cpdNumAlgos(); ++algoIndex) {
auto table = vtkSmartPointer<vtkTable>::New();
algoTables.push_back(table);
vtkSmartPointer<vtkFloatArray> arrX = vtkSmartPointer<vtkFloatArray>::New();
arrX->SetName("X Axis");
table->AddColumn(arrX);
int lineIndex = m_cpdTables.size();
for (int i = 0; i < numCols; ++i) {
vtkSmartPointer<vtkFloatArray> arrC = vtkSmartPointer<vtkFloatArray>::New();
auto name = "DepthChart-CpD-" + std::to_string(lineIndex) + "-" + std::to_string(algoIndex) +
"-" + std::to_string(i);
arrC->SetName(name.c_str());
table->AddColumn(arrC);
}
table->SetNumberOfRows(numPoints);
for (int i = 0; i < numPoints; ++i) {
table->SetValue(i, 0, i);
}
}
m_cpdTables.push_back(algoTables);
}
for (uint dataIndex = 0; dataIndex < m_vtkFboItem->model()->cpdFrameCount(); ++dataIndex) {
auto data = m_vtkFboItem->model()->cpdData(dataIndex).second;
assert(data.size() == m_vtkFboItem->model()->cpdLineLabels().size());
for (auto & vec2_point : data) {
assert(vec2_point.size() == m_vtkFboItem->model()->cpdNumAlgos());
for (auto & vec_point : vec2_point) {
assert(vec_point.size() == (uint)numPoints);
}
}
for (uint lineIndex = 0; lineIndex < m_cpdTables.size(); ++lineIndex) {
for (uint algoIndex = 0; algoIndex < m_cpdTables[lineIndex].size(); ++algoIndex) {
for (int depthIndex = 0; depthIndex < numPoints; ++depthIndex) {
m_cpdTables[lineIndex][algoIndex]->SetValue(depthIndex, dataIndex + 1,
data[lineIndex][algoIndex][depthIndex]);
}
}
}
}
}
// Update existence of BpD plot
if (m_bpdLine == nullptr && m_vtkFboItem->model()->showBpD()) {
m_bpdLine = m_chart->AddPlot(vtkChart::LINE);
m_bpdLine->SetColor(255, 0, 0, 255);
m_bpdLine->SetWidth(2.0);
} else if (m_bpdLine != nullptr && !m_vtkFboItem->model()->showBpD()) {
m_chart->RemovePlot(m_chart->GetPlotIndex(m_bpdLine));
m_bpdLine->Delete();
m_bpdLine = nullptr;
}
// Update existence of CpD plot
if (m_cpdLines.size() == 0 && m_vtkFboItem->model()->showCpD()) {
for (uint lineIndex = 0; lineIndex < m_cpdTables.size(); ++lineIndex) {
std::vector<vtkPlot *> algoLines;
for (uint algoIndex = 0; algoIndex < m_cpdTables[lineIndex].size(); ++algoIndex) {
auto cpdLine = m_chart->AddPlot(vtkChart::LINE);
cpdLine->SetColor(r[lineIndex], g[lineIndex], b[lineIndex], 255);
cpdLine->SetWidth(1.0);
m_chart->SetPlotCorner(cpdLine, 1);
algoLines.push_back(cpdLine);
}
m_cpdLines.push_back(algoLines);
}
} else if (m_cpdLines.size() != 0 && !m_vtkFboItem->model()->showCpD()) {
for (uint lineIndex = 0; lineIndex < m_cpdLines.size(); ++lineIndex) {
for (uint algoIndex = 0; algoIndex < m_cpdLines[lineIndex].size(); ++algoIndex) {
auto line = m_cpdLines[lineIndex][algoIndex];
m_chart->RemovePlot(m_chart->GetPlotIndex(line));
line->Delete();
}
}
m_cpdLines.clear();
}
// Update data of plots
if (m_vtkFboItem != nullptr && m_vtkFboItem->model() != nullptr) {
if (m_vtkFboItem->model()->showBpD()) {
uint frameNumber = 0;
if (m_vtkFboItem->m_animationId.compare("") != 0) {
frameNumber = m_bpdAnimationFrames[m_vtkFboItem->m_animationId][m_vtkFboItem->m_animationFrame];
} else if (m_vtkFboItem->m_realTime != m_realTime) {
frameNumber = m_vtkFboItem->model()->bpdFrameForTime(m_vtkFboItem->m_realTime);
}
m_bpdLine->SetInputData(m_bpdTable, 0, frameNumber + 1);
}
if (m_vtkFboItem->model()->showCpD()) {
uint frameNumber = 0;
if (m_vtkFboItem->m_animationId.compare("") != 0) {
frameNumber = m_cpdAnimationFrames[m_vtkFboItem->m_animationId][m_vtkFboItem->m_animationFrame];
} else if (m_vtkFboItem->m_realTime != m_realTime) {
frameNumber = m_vtkFboItem->model()->cpdFrameForTime(m_vtkFboItem->m_realTime);
}
for (uint lineIndex = 0; lineIndex < m_cpdLines.size(); ++lineIndex) {
for (uint algoIndex = 0; algoIndex < m_cpdLines[lineIndex].size(); ++algoIndex) {
m_cpdLines[lineIndex][algoIndex]->SetInputData(m_cpdTables[lineIndex][algoIndex], 0,
frameNumber + 1);
}
}
}
m_chart->RecalculateBounds();
}
if (!m_view) {
// Set up the view
m_view = vtkSmartPointer<vtkContextView>::New();
m_view->SetRenderWindow(m_vtkRenderWindow);
m_view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
m_view->GetScene()->AddItem(m_chart);
m_view->GetInteractor()->Initialize();
m_view->GetInteractor()->Start();
}
}
void DepthChartRenderer::render()
{
m_vtkRenderWindow->PushState();
this->openGLInitState();
m_vtkRenderWindow->Start();
if (m_firstRender) {
this->initScene();
m_firstRender = false;
}
// Render
m_vtkRenderWindow->Render();
m_vtkRenderWindow->PopState();
m_vtkFboItem->window()->resetOpenGLState();
}
void DepthChartRenderer::openGLInitState()
{
m_vtkRenderWindow->OpenGLInitState();
m_vtkRenderWindow->MakeCurrent();
QOpenGLFunctions::initializeOpenGLFunctions();
QOpenGLFunctions::glEnable(GL_MULTISAMPLE);
QOpenGLFunctions::glEnable(GL_LINE_SMOOTH);
QOpenGLFunctions::glUseProgram(0);
}
QOpenGLFramebufferObject * DepthChartRenderer::createFramebufferObject(const QSize & size)
{
QSize macSize = QSize(size.width() / 2, size.height() / 2);
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::Depth);
#ifdef Q_OS_MAC
std::unique_ptr<QOpenGLFramebufferObject> framebufferObject(new QOpenGLFramebufferObject(macSize, format));
#else
std::unique_ptr<QOpenGLFramebufferObject> framebufferObject(new QOpenGLFramebufferObject(size, format));
#endif
m_vtkRenderWindow->SetBackLeftBuffer(GL_COLOR_ATTACHMENT0);
m_vtkRenderWindow->SetFrontLeftBuffer(GL_COLOR_ATTACHMENT0);
m_vtkRenderWindow->SetBackBuffer(GL_COLOR_ATTACHMENT0);
m_vtkRenderWindow->SetFrontBuffer(GL_COLOR_ATTACHMENT0);
m_vtkRenderWindow->SetSize(framebufferObject->size().width(), framebufferObject->size().height());
m_vtkRenderWindow->SetOffScreenRendering(true);
m_vtkRenderWindow->Modified();
return framebufferObject.release();
}
void DepthChartRenderer::initScene() { m_vtkRenderWindow->SetOffScreenRendering(true); }
I'm running this on the newest Macbook Pro 2018 with Qt 5.11.1 and VTK 8.1.1. I can't think of any other useful information at the moment. If there is anything else I can provide, please let me know. I feel like it has to do with something in the QQuickFramebufferObject
surface formatting, since I can run vtk qt examples just fine, but I don't know what to look for anymore.