Question

I'm looking for a way to control the opaque object render order when multiple objects (Xrays/Image3D) share the same Z plane. I've been looking at possibly reordering the PropArray in a custom OpaquePass but I am curious if others have a cleaner procedure for this. Unfortunately using Image2D is not an option despite it having the SetDisplayLocationToForeground/BackGround() method.

Is their a cleaner way to go about this than injecting our own render code with a custom OpaquePass? The user of the software will have the ability to change the render order of xrays through bringToFront/Back controls.

I've been able to successfully test this behavior in WebGL and Three.js which exposes control of the render order. Ex: enter image description here

Note: I'm using Python (2.7.5) along with the Python Vtk: 5.10.1

Was it helpful?

Solution

After a month of development and troubleshooting I've solved it!

Here is how I solved the render depth issue in VTK.

Note: This will only solve render depth for objects that are in the same z-depth. Objects in front or behind will draw normally despite having a render depth.

The Logic

We will edit the draw order in the vtkRenderer's viewProps object. All vtkObjects with a render depth of null will be drawn first followed by a descending order of render depths.

Example:
Unsorted render depths
viewProps = [ NULL, 3, NULL, 1, 2, 4, NULL]

Sorted render depths
viewProps = [ NULL, NULL, NULL, 4, 3, 2, 1]

The Implementation

Add a property to vtkObject called "renderDepth" with Get/Set methods. On vtkObject creation set renderDepth = NULL;

In vtkRenderer create a method (I'll call mine RenderDepthSort).

Recursively call down viewProp object tree then simple bubble sort to swap any items with render depths. vtkRenderer::RenderDepthSort(vtkPropCollection * propArray){ propArray->InitTraversal(); for(int i=0; i < propArray->GetNumberOfItems(); i++){ vtkProp * prop = propArray->GetNextProp(); if(prop->IsA("vtkAssembly")){ vtkAssembly * ptr = static_cast<vtkAssembly *>(prop); if(ptr->GetParts()->GetNumberOfItems() > 0) this->RenderDepthSort(ptr->GetParts()); } } bool isUnsorted = true; while(isUnsorted){ isUnsorted = false; propArray->InitTraversal(); for(int i=0; i < propArray->GetNumberOfItems()-1; i++){ vtkProp * propA = propArray->GetNextProp(); vtkProp * propB = static_cast<vtkProp *>(propArray->GetItemAsObject(i+1));

  if(propA->GetRenderDepth() == NULL || propB->GetRenderDepth() == NULL){
    if(propA->GetRenderDepth() != NULL && propB->GetRenderDepth() == NULL){
      propArray->ReplaceItem(i, propB);
      propArray->ReplaceItem(i+1, propA);
      isUnsorted = true;
    }
  }else if(propA->GetRenderDepth() < propB->GetRenderDepth()){
    propArray->ReplaceItem(i, propB);
    propArray->ReplaceItem(i+1, propA);
    isUnsorted = true;
  }
} //end for loop

} // end while }//end renderDepthSort Method

If you've abstracted out your vtk implementation like we had done and you don't have complete control of your vtkViewProps then implemented another method to solve the render depths and propagate them up the tree.

void vtkRenderer::InitSolveRenderDepths(vtkPropCollection * propArray){ int depth = NULL; int numDepths = 0; propArray->InitTraversal(); for(int i=0; i < propArray->GetNumberOfItems(); i++){ vtkProp * prop = propArray->GetNextProp(); if(prop->IsA("vtkAssembly")){ this->SolveRenderDepths(prop); int temp = prop->GetRenderDepth(); if(temp != NULL){ if(temp < depth || depth == NULL){ depth = temp; } numDepths++; } } } }

Finally
Create one more method called UpdateDrawOrder()
void vtkRenderer::UpdateDrawOrder(){ vtkPropCollection * props = this->GetViewProps(); this->InitSolveRenderDepths(props); this->RenderDepthSort(props); }

Set this up to call UpdateDrawOrder in the vtkRenderer::Render() or on your vtkRenderer object.

Z End!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top