
.
vtkCellPicker has the interface int vtkPicker::Pick(double selectionX, double selectionY, double selectionZ, vtkRenderer* renderer)
.
In the some scenes, we can still pick the 3D actor even if pass wrong vtkRenderer object to the interface.
Here is a simple example we can use to test it.
#include "worker.h"
#include "Log.hpp"
#include "CustomIteractorStyle.h"
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
Worker::Worker()
{
#ifdef __EMSCRIPTEN__
m_RenderWindowInteractor = vtkSPtr<vtkSDL2RenderWindowInteractor>::New();
m_RenderWindow = vtkSPtr<vtkSDL2OpenGLRenderWindow>::New();
#else
m_RenderWindowInteractor = vtkSPtr<vtkRenderWindowInteractor>::New();
m_RenderWindow = vtkSPtr<vtkRenderWindow>::New();
#endif
m_Picker = vtkSPtr<vtkCellPicker>::New();
m_Picker->PickFromListOn();
}
void Worker::Init()
{
vtkSPtrNew( cone, vtkConeSource );
vtkSPtrNew( mapper, vtkPolyDataMapper );
mapper->SetInputConnection( cone->GetOutputPort() );
m_Actor = vtkSPtr<vtkActor>::New();
m_Actor->SetMapper( mapper );
m_Renderer = vtkSPtr<vtkRenderer>::New();
m_Renderer->SetBackground( 0, 0.2, 0 );
m_Renderer->SetLayer( 0 );
m_TopRenderer = vtkSPtr<vtkRenderer>::New();
m_TopRenderer->SetLayer( 1 );
//m_TopRenderer->SetActiveCamera( m_Renderer->GetActiveCamera() );
m_TopRenderer->AddActor(m_Actor);
m_RenderWindow->AddRenderer( m_Renderer );
m_RenderWindow->AddRenderer( m_TopRenderer );
m_RenderWindow->SetNumberOfLayers( 2 );
m_RenderWindowInteractor->SetRenderWindow( m_RenderWindow );
vtkSPtrNew( iStyle, CustomIteractorStyle );
iStyle->Setm_Worder( this );
m_RenderWindowInteractor->SetInteractorStyle( iStyle );
m_Renderer->ResetCamera();
m_RenderWindow->Render();
m_Picker->AddPickList( m_Actor );
Log( IInfo, "Init!" );
}
void Worker::Start()
{
m_RenderWindowInteractor->Start();
Log( IInfo, "Start!" );
}
void Worker::OnLeftButtonDown()
{
auto eventPos = m_RenderWindowInteractor->GetEventPosition();
auto pickResult = m_Picker->Pick(eventPos[0], eventPos[1], 0, m_Renderer);
Log( IInfo, "pickResult: ", pickResult );
if (m_Picker->GetPointId() > -1 )
{
vtkSPtr<vtkActor> actor = m_Picker->GetActor();
Log( IInfo, "actor: ", actor );
}
}
We can pick the cone at some bad positions:
.
vtkPicker will use renderer object to compute the tolerance and help us to get the props list (if PickFromList flag in vtkPicker is false).
int vtkPicker::Pick(double selectionX, double selectionY, double selectionZ, vtkRenderer* renderer)
<--
int result = this->Pick3DInternal(renderer, p1World, p2World);
<---
int vtkPicker::Pick3DInternal(vtkRenderer* renderer, double p1World[4], double p2World[4])
{
//...
renderer->SetWorldPoint(0.5 * (p1World[0] + p2World[0]), 0.5 * (p1World[1] + p2World[1]),
0.5 * (p1World[2] + p2World[2]), 1.0);
renderer->WorldToDisplay();
double* displayCoords = renderer->GetDisplayPoint();
double tolZ = displayCoords[2];
//...
x = winSize[0] * viewport[0];
y = winSize[1] * viewport[1];
renderer->SetDisplayPoint(x, y, tolZ);
renderer->DisplayToWorld();
renderer->GetWorldPoint(windowLowerLeft);
x = winSize[0] * viewport[2];
y = winSize[1] * viewport[3];
renderer->SetDisplayPoint(x, y, tolZ);
renderer->DisplayToWorld();
renderer->GetWorldPoint(windowUpperRight);
//...
vtkPropCollection* props;
vtkProp* propCandidate;
if (this->PickFromList)
{
props = this->GetPickList();
}
else
{
props = renderer->GetViewProps();
}
//...
So if we set m_Picker->PickFromListOn();
,the wrong renderer will just affects the picking tolerance.
After setting the same active camera for the both renderers, the wrong vtkRenderer object can work fine just as the right renderer.
m_TopRenderer->SetActiveCamera( m_Renderer->GetActiveCamera() );
.
All code files of the example can been found at:
https://github.com/theArcticOcean/tutorials/tree/main/learnWebAssembly/cellPickerInWrongRenderer
It can work as a web app (wasm) and a desktop application (exe).