Skip to content

Commit 056dd9a

Browse files
committed
Fix picking when using QVTKOpenGLWidget
Picking both 2D and 3D actors could fail when using QVTKOpenGLWidget. This commit fixes picking by ensuring that the framebuffer object that VTK renders into is bound at the start picking operations.
1 parent a70f6bd commit 056dd9a

File tree

5 files changed

+202
-0
lines changed

5 files changed

+202
-0
lines changed

GUISupport/Qt/QVTKOpenGLWidget.cxx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ class QVTKOpenGLWidgetObserver : public vtkCommand
9494
break;
9595

9696
case vtkCommand::StartEvent:
97+
VTK_FALLTHROUGH;
98+
case vtkCommand::StartPickEvent:
9799
this->Target->startEventCallback();
98100
break;
99101
}
@@ -197,6 +199,7 @@ void QVTKOpenGLWidget::SetRenderWindow(vtkGenericOpenGLRenderWindow* win)
197199
this->RenderWindow->AddObserver(vtkCommand::WindowIsCurrentEvent, this->Observer.Get());
198200
this->RenderWindow->AddObserver(vtkCommand::WindowFrameEvent, this->Observer.Get());
199201
this->RenderWindow->AddObserver(vtkCommand::StartEvent, this->Observer.Get());
202+
this->RenderWindow->AddObserver(vtkCommand::StartPickEvent, this->Observer.Get());
200203

201204
if (this->FBO)
202205
{

GUISupport/Qt/Testing/Cxx/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ if(VTK_QT_VERSION VERSION_GREATER "4" AND
1818
TestQVTKOpenGLWidget.cxx
1919
TestQVTKOpenGLWidgetWithMSAA.cxx
2020
)
21+
vtk_add_test_cxx(${vtk-module}CxxTests tests
22+
NO_VALID
23+
TestQVTKOpenGLWidgetPicking.cxx
24+
)
2125
endif()
2226

2327
if(WIN32)
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/*=========================================================================
2+
3+
Program: Visualization Toolkit
4+
Module: TestQVTKOpenGLWidgetPicking.cxx
5+
6+
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7+
All rights reserved.
8+
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9+
10+
This software is distributed WITHOUT ANY WARRANTY; without even
11+
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12+
PURPOSE. See the above copyright notice for more information.
13+
14+
=========================================================================*/
15+
// Tests picking actors with QVTKOpenGLWidget and vtkPropPicker.
16+
17+
#include "QVTKOpenGLWidget.h"
18+
#include "vtkActor2D.h"
19+
#include "vtkCamera.h"
20+
#include "vtkCoordinate.h"
21+
#include "vtkGenericOpenGLRenderWindow.h"
22+
#include "vtkMath.h"
23+
#include "vtkPolyDataMapper2D.h"
24+
#include "vtkProperty2D.h"
25+
#include "vtkPropPicker.h"
26+
#include "vtkRenderer.h"
27+
#include "vtkSphereSource.h"
28+
29+
#include <QApplication>
30+
#include <QSurfaceFormat>
31+
32+
#include <algorithm>
33+
#include <cmath>
34+
#include <vector>
35+
36+
int TestQVTKOpenGLWidgetPicking(int argc, char* argv[])
37+
{
38+
// Disable multisampling
39+
vtkOpenGLRenderWindow::SetGlobalMaximumNumberOfMultiSamples(0);
40+
QSurfaceFormat::setDefaultFormat(QVTKOpenGLWidget::defaultFormat());
41+
42+
QApplication app(argc, argv);
43+
44+
QVTKOpenGLWidget widget;
45+
widget.resize(300, 300);
46+
47+
auto renWin = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New();
48+
widget.SetRenderWindow(renWin);
49+
50+
auto interactor = renWin->GetInteractor();
51+
52+
auto ren = vtkSmartPointer<vtkRenderer>::New();
53+
ren->GradientBackgroundOn();
54+
ren->SetBackground2(0.7, 0.7, 0.7);
55+
renWin->AddRenderer(ren);
56+
57+
interactor->Render();
58+
59+
const int NumSpheres = 5;
60+
const double SphereRadius = 0.5;
61+
62+
// Add spheres arranged in a circle
63+
std::vector<vtkSmartPointer<vtkActor2D> > actors;
64+
const double Pi2 = 2.0 * vtkMath::Pi();
65+
const double step = Pi2 / NumSpheres;
66+
for (double theta = 0.0; theta < Pi2; theta += step)
67+
{
68+
auto source = vtkSmartPointer<vtkSphereSource>::New();
69+
const double x = sin(theta);
70+
const double y = cos(theta);
71+
const double z = 0.0;
72+
source->SetRadius(SphereRadius);
73+
source->SetCenter(x, y, z);
74+
75+
auto coordinate = vtkSmartPointer<vtkCoordinate>::New();
76+
coordinate->SetCoordinateSystemToWorld();
77+
78+
auto mapper = vtkSmartPointer<vtkPolyDataMapper2D>::New();
79+
mapper->SetInputConnection(source->GetOutputPort());
80+
mapper->SetTransformCoordinate(coordinate);
81+
82+
auto actor = vtkSmartPointer<vtkActor2D>::New();
83+
actor->SetMapper(mapper);
84+
actor->GetProperty()->SetColor(0.62, 0.81, 0.62);
85+
ren->AddActor(actor);
86+
actors.push_back(actor);
87+
}
88+
89+
ren->GetActiveCamera()->SetPosition(0.0, 0.0, 9.0);
90+
91+
widget.show();
92+
app.processEvents();
93+
94+
auto picker = vtkSmartPointer<vtkPropPicker>::New();
95+
96+
auto coordinate = vtkSmartPointer<vtkCoordinate>::New();
97+
coordinate->SetCoordinateSystemToWorld();
98+
99+
// Pick at sphere centers
100+
std::vector<vtkSmartPointer<vtkActor2D> > hits;
101+
for (double theta = 0.0; theta < Pi2; theta += step)
102+
{
103+
const double x = sin(theta);
104+
const double y = cos(theta);
105+
const double z = 0.0;
106+
coordinate->SetValue(x, y, z);
107+
108+
const int* display = coordinate->GetComputedDisplayValue(ren);
109+
picker->Pick(display[0], display[1], 0.0, ren);
110+
auto actor = picker->GetActor2D();
111+
if (actor)
112+
{
113+
actor->GetProperty()->SetColor(0.89, 0.81, 0.67);
114+
}
115+
hits.push_back(actor);
116+
117+
interactor->Render();
118+
app.processEvents();
119+
}
120+
121+
// Pick outside of spheres
122+
std::vector<vtkSmartPointer<vtkActor2D> > misses;
123+
for (double theta = 0.0; theta < Pi2; theta += (0.5 * step))
124+
{
125+
const double x = 2.0 * sin(theta);
126+
const double y = 2.0 * cos(theta);
127+
const double z = 0.0;
128+
coordinate->SetValue(x, y, z);
129+
130+
const int* display = coordinate->GetComputedDisplayValue(ren);
131+
picker->Pick(display[0], display[1], 0.0, ren);
132+
auto actor = picker->GetActor2D();
133+
if (actor)
134+
{
135+
actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
136+
}
137+
misses.push_back(actor);
138+
139+
interactor->Render();
140+
app.processEvents();
141+
}
142+
143+
// Pick in center of window
144+
{
145+
coordinate->SetValue(0.0, 0.0, 0.0);
146+
const int* display = coordinate->GetComputedDisplayValue(ren);
147+
148+
picker->Pick(display[0], display[1], 0.0, ren);
149+
auto actor = picker->GetActor2D();
150+
if (actor)
151+
{
152+
actor->GetProperty()->SetColor(1.0, 0.0, 0.0);
153+
}
154+
misses.push_back(actor);
155+
156+
interactor->Render();
157+
app.processEvents();
158+
}
159+
160+
// Check that picks on spheres hit correct actors
161+
bool hitsOk = (hits == actors);
162+
if (!hitsOk)
163+
{
164+
std::cout << "ERROR: Picking actors failed" << std::endl;
165+
return EXIT_FAILURE;
166+
}
167+
168+
// Check that picks outside of spheres hit no actors
169+
bool missesOk = std::all_of(misses.begin(), misses.end(),
170+
[](const vtkSmartPointer<vtkActor2D> & actor) { return (actor == nullptr); });
171+
if (!missesOk)
172+
{
173+
std::cout << "ERROR: Picking outside of actors failed" << std::endl;
174+
return EXIT_FAILURE;
175+
}
176+
177+
return EXIT_SUCCESS;
178+
}

Rendering/OpenGL2/vtkGenericOpenGLRenderWindow.cxx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,3 +244,14 @@ void vtkGenericOpenGLRenderWindow::Render()
244244
this->RestoreGLState();
245245
}
246246
}
247+
248+
void vtkGenericOpenGLRenderWindow::SetIsPicking(int isPicking)
249+
{
250+
vtkDebugMacro(<< this->GetClassName() << " (" << this << "): setting IsPicking to " << isPicking); \
251+
if (this->IsPicking != isPicking)
252+
{
253+
this->IsPicking = isPicking;
254+
this->Modified();
255+
this->InvokeEvent(this->IsPicking ? vtkCommand::StartPickEvent : vtkCommand::EndPickEvent, nullptr);
256+
}
257+
}

Rendering/OpenGL2/vtkGenericOpenGLRenderWindow.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,12 @@ class VTKRENDERINGOPENGL2_EXPORT vtkGenericOpenGLRenderWindow :
156156
*/
157157
vtkSetVector2Macro(ScreenSize,int);
158158

159+
/**
160+
* Overridden to invoke vtkCommand::StartPickEvent and
161+
* vtkCommand::EndPickEvent.
162+
*/
163+
void SetIsPicking(int isPicking) VTK_OVERRIDE;
164+
159165
protected:
160166
int DirectStatus;
161167
int SupportsOpenGLStatus;

0 commit comments

Comments
 (0)