Thanks for the suggestion. Yes, using locators is one of the options we are considering to speed up picking. It requires some extra bookkeeping and hardware-based picking could be still faster. Therefore, if VTK hardware pickers could be improved to pick on semi-transparent meshes (pick the point wherever the opacity reaches the specified threshold) then that may be a simpler solution for us.
Of course, itās my very own problem. What was I thinking going through the trouble of making the figures, bothering people here, etc, right? Then I think Iām better off downgrading to 8.2 for now, and if I stumble upon something new Iāll update this topic and the upstream issue. Thanks for your time.
Yes, this is always hard. Everyone has a lot on their plate, so you need to make a lot of effort to get people involved. You need to make the problem interesting and simple enough (so that when someone reads your post on a smartphone while waiting for a bus would start thinking on it), make the questions very focused, trying to keep it short, but still provide enough details, etc. You may still end up being unlucky and not to get too much useful help.
You can also try again in a few weeks, maybe post a new topic, present the problem again a bit differently, with a small reproducible example, maybe someone will bite. Iāll not respond to that topic and weāll see if that will encourage others to step in.
If things are urgent or mission-critical then you can always contract Kitware (we bought small support packages occasionally when got stuck and things worked out OK) or someone else to investigate and fix some problems for you. Or just wait for someone else come across the issue and figure out a solution.
It seems that the bug is caused by this OpenGL call in vtkOpenGLRenderWindow::GetZBufferData(int,int,int,int,float*)
:
glReadPixels(x_low, y_low, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, z_data);
When called by vtkRenderer::GetZ(int,int)
, it returns (via z_data
pointer) a Z value of 1.0, which causes the code in vtkWorldPointPicker::Pick( double, double, double, vtkRenderer*)
to assume there was an error and, hence, use the cameraās focal point as pick location instead. This explains the observed results.
Curiously, glReadPixels
returns the correct Z-buffer value when GetZBufferData()
is called from vtkHardwareSelector::BuildPropHitList(unsigned char*)
.
It is also important to stress the fact that the code of GetZBufferData()
in VTK 9 is quite different than that of VTK 8.1.
Hard assigning the Z value with a valid value (e.g. 0.78533469389) via debugger results in the correct behavior (correct pick world coordinates).
It seems that we have a diagnosis. I hope that its fix does not involve rolling the GetZBufferData()
code back to its VTK 8 version.
During a single pick operation, vtkOpenGLRenderWindow::GetZBufferData(int,int,int,int,float*)
is called thrice. Twice from vtkHardwareSelector::BuildPropHitList(unsigned char*)
(with correct Z value) and one from vtkRenderer::GetZ(int,int)
with the incorrect Z value.
By the 3rd call to vtkOpenGLRenderWindow::GetZBufferData(int,int,int,int,float*)
(the one made by GetZ()
), glIsEnabled( GL_DEPTH_TEST )
returns GL_FALSE
, hence it fails. Itās likely a due prior call to glEnable( GL_DEPTH_TEST )
is missing.
Ref.: c++ - glReadPixels depth_buffer_component always returns 1 - Stack Overflow
glGetDoublev( GL_DEPTH_RANGE, depth_range );
returns the expected values of 0.0
and 1.0
everytime, so the bug is likely caused by a missing prior call to glEnable( GL_DEPTH_TEST )
.
Rewriting vtkRenderer::GetZ(int x, int y)
and rebuilding VTK solves the issue:
// Given a pixel location, return the Z value
double vtkRenderer::GetZ(int x, int y)
{
double z;
// use a hardware selector beacuse calling this->RenderWindow->GetZbufferData(int,int,int,int) directly
// from here always results in a z-buffer value of 1.0, meaning it is using a cleared depth buffer.
{
vtkNew<vtkHardwareSelector> hsel;
hsel->SetActorPassOnly(true);
hsel->SetCaptureZValues(true);
hsel->SetRenderer(this);
hsel->SetArea(x, y, x, y);
vtkSmartPointer<vtkSelection> sel;
sel.TakeReference(hsel->Select());
// find the closest z-buffer value
if (sel && sel->GetNode(0))
{
vtkProp* closestProp = nullptr;
double closestDepth = 1.0;
unsigned int numPicked = sel->GetNumberOfNodes();
for (unsigned int pIdx = 0; pIdx < numPicked; pIdx++)
{
vtkSelectionNode* selnode = sel->GetNode(pIdx);
double adepth = selnode->GetProperties()->Get(vtkSelectionNode::ZBUFFER_VALUE());
if (adepth < closestDepth)
closestDepth = adepth;
}
z = closestDepth;
}
}
return z;
}
Calling vtkRenderWindow::GetZbufferData(int,int,int,int)
in that context always results in Z-buffer values of 1.0, meaning the depth buffer is reset in that context.
Paulo, Can you file a merge request and link to this discussion. If it passes all the tests we can merge this. Thanks!
Very good detective work, @Paulo_Carvalho!
I donāt think that replacing a simple lightweight this->RenderWindow->GetZbufferData
call by a full-blown hardware picking (including instantiating multiple objects, a for loop etc.) would be acceptable. But hopefully all the information that you provided should be sufficient for a VTK rendering expert (@ken-martin, @sankhesh,ā¦?) to see what the problem is and how could it be addressed.
It might be just a matter of documentation, which explains when vtkPropPicker/vtkWorldPicker::Pick
method can be called; or maybe vtkWorldPointPicker::Pick
method could be made more robust (e.g., enable GL_DEPTH_TEST
?).
Here: https://gitlab.kitware.com/vtk/vtk/-/merge_requests/9125 . Thanks.
Thanks. True. Well, a fast code that doesnāt yield the correct result is of no use and shouldnāt be left broken if a working version is known, even if it is apparently slower. The z-buffer is somehow reset before that call. I modified the code to reset the depth buffer to 0.424242 instead of 1.0 and I was starting to get 0.424242 for every GetZ()
call. Anyway, I did picking on a large vtkUnstructuredGrid
with millions of cells and I couldnāt notice any performance worsening. Picking that large model was as slow as before. But now we are back getting the correct pick world coordinates.
Of course, if someone can improve that answer, she/he will be quite welcome.
It appears that depth testing gets disabled in the OpenGL state as @Paulo_Carvalho discovered. Couldnāt tell based on a cursory look where that happens but will try to dig into it a little unless @ken-martin already has idea where this could be coming from.
Hi, recently I upgrade my vtk to 9.1, So I am interested in this topic, but is there any official solution ?
Well, the merge request is still open. So, as far as I know, there is no solution avaliable downstream yet. If you canāt wait, you can patch the vtkRenderer::GetZ(int,int)
in the VTK code (vtkrenderer.cxx
source file) yourself.
@Paulo_Carvalho
It looks like this problem is still present in vtk 9.2.6, OSX (here to reproduce it). Most widgets are broken.
Is there a workaround in python?
Hello,
Unfortunatelly, the merge request is still open. If you build VTK from sources, you can use my VTK fork containing the branch with the fix: https://gitlab.kitware.com/PauloCarvalhoRJ/vtk/-/tree/Bugfix_vtkRenderer_GetZ . I just updated my VTK fork with the latest commits from upstream.
best,
PC
Update:
After more than a year attempting to make the fix into downstream, I closed the merge request as I canāt afford the time to tender it undefinitely. Anyone in need can still use my fork to compile VTK with the fix: https://gitlab.kitware.com/PauloCarvalhoRJ/vtk/-/tree/Bugfix_vtkRenderer_GetZ or simply patch the source file as instructed further above.
all the best,
PC
Thanks for merging this. I updated the solution answer.