...
 
Commits (2)
  • Ken Martin's avatar
    Fixes to translucent Rendering · 9c70c2b9
    Ken Martin authored
    Try to fix some issues show in
    vtk/vtk#17404 as well as
    other transparency issues with vtkCompositePolyDataMapper2
    
    Previously mappers could only report GetIsOpaque which would render them
    as opaque or transparent. With this change mappers can report if they
    have TranslucentPolygonalGeometry as well as OpaqueGeometry and they can
    report both. If they report both they will get invoked on both passes.
    This allows complex mapperssuch as CPDM2 to do render some blocks during
    the opaque pass and other blocks during the translucent pass.
    
    Create better logic in vtkScalarsToColors to report If the scalar
    mapping would produce translucent results and use that logic in a couple
    places where it had been duplicated.
    9c70c2b9
  • Ken Martin's avatar
    Merge topic 'translucency_fix' · 41d1dc0e
    Ken Martin authored
    9c70c2b9 Fixes to translucent Rendering
    Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
    Merge-request: !5745
    41d1dc0e
......@@ -119,6 +119,21 @@ int vtkLookupTable::IsOpaque()
return this->OpaqueFlag;
}
int vtkLookupTable::IsOpaque(vtkAbstractArray *scalars,
int colorMode, int component)
{
// use superclass logic?
vtkDataArray *dataArray = vtkArrayDownCast<vtkDataArray>(scalars);
if ((colorMode == VTK_COLOR_MODE_DEFAULT &&
vtkArrayDownCast<vtkUnsignedCharArray>(dataArray) != nullptr) ||
(colorMode == VTK_COLOR_MODE_DIRECT_SCALARS && dataArray))
{
return this->Superclass::IsOpaque(scalars, colorMode, component);
}
// otherwise look at our table
return this->IsOpaque();
}
//----------------------------------------------------------------------------
void vtkLookupTable::SetTableRange(const double r[2])
{
......
......@@ -90,11 +90,15 @@ public:
vtkTypeMacro(vtkLookupTable,vtkScalarsToColors);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Return true if all of the values defining the mapping have an opacity
* equal to 1.
*/
int IsOpaque() override;
int IsOpaque(vtkAbstractArray *scalars,
int colorMode, int component) override;
//@}
/**
* Allocate a color table of specified size.
......
......@@ -80,6 +80,48 @@ int vtkScalarsToColors::IsOpaque()
return 1;
}
//----------------------------------------------------------------------------
// Description:
// Return true if all of the values defining the mapping have an opacity
// equal to 1. Default implementation return true.
int vtkScalarsToColors::IsOpaque(vtkAbstractArray *scalars,
int colorMode, int /*component*/)
{
if (!scalars)
{
return this->IsOpaque();
}
int numberOfComponents = scalars->GetNumberOfComponents();
vtkDataArray *dataArray = vtkArrayDownCast<vtkDataArray>(scalars);
// map scalars through lookup table only if needed
if ((colorMode == VTK_COLOR_MODE_DEFAULT &&
vtkArrayDownCast<vtkUnsignedCharArray>(dataArray) != nullptr) ||
(colorMode == VTK_COLOR_MODE_DIRECT_SCALARS && dataArray))
{
// we will be using the scalars directly, so look at the number of
// components and the range
if (numberOfComponents == 3 || numberOfComponents == 1)
{
return (this->Alpha >= 1.0 ? 1 : 0);
}
// otherwise look at the range of the alpha channel
unsigned char opacity = 0;
switch (scalars->GetDataType())
{
vtkTemplateMacro(
vtkScalarsToColors::ColorToUChar(
static_cast<VTK_TT>(dataArray->GetRange(numberOfComponents - 1)[0]),
&opacity));
}
return ((opacity == 255) ? 1 : 0);
}
return 1;
}
//----------------------------------------------------------------------------
void vtkScalarsToColors::SetVectorModeToComponent()
{
......
......@@ -64,11 +64,16 @@ public:
void PrintSelf(ostream& os, vtkIndent indent) override;
static vtkScalarsToColors *New();
//@{
/**
* Return true if all of the values defining the mapping have an opacity
* equal to 1. Default implementation returns true.
* equal to 1. Default implementation returns true. The more complex
* signature will yield more accurate results.
*/
virtual int IsOpaque();
virtual int IsOpaque(vtkAbstractArray *scalars,
int colorMode, int component);
//@}
/**
* Perform any processing required (if any) before processing
......
......@@ -54,6 +54,7 @@ vtkActor::vtkActor()
this->ForceOpaque = false;
this->ForceTranslucent = false;
this->InTranslucentPass = false;
// The mapper bounds are cache to know when the bounds must be recomputed
// from the mapper bounds.
......@@ -106,15 +107,12 @@ void vtkActor::GetActors(vtkPropCollection *ac)
ac->AddItem(this);
}
//----------------------------------------------------------------------------
// should be called from the render methods only
int vtkActor::GetIsOpaque()
vtkTypeBool vtkActor::HasOpaqueGeometry()
{
if (this->ForceOpaque)
{
return 1;
}
if (this->ForceTranslucent)
{
return 0;
......@@ -134,11 +132,54 @@ int vtkActor::GetIsOpaque()
// are we using an opaque scalar array, if any?
is_opaque = is_opaque &&
(this->Mapper == nullptr || this->Mapper->GetIsOpaque());
(this->Mapper == nullptr || this->Mapper->HasOpaqueGeometry());
return is_opaque? 1 : 0;
}
vtkTypeBool vtkActor::HasTranslucentPolygonalGeometry()
{
if (this->ForceOpaque)
{
return 0;
}
if (this->ForceTranslucent)
{
return 1;
}
// make sure we have a property
if(!this->Property)
{
// force creation of a property
this->GetProperty();
}
if (this->Property->GetOpacity() < 1.0)
{
return 1;
}
if (this->Texture != nullptr && this->Texture->IsTranslucent())
{
return 1;
}
if (this->Mapper != nullptr && this->Mapper->HasTranslucentPolygonalGeometry())
{
return 1;
}
return 0;
}
//----------------------------------------------------------------------------
// should be called from the render methods only
int vtkActor::GetIsOpaque()
{
return this->HasOpaqueGeometry();
}
//----------------------------------------------------------------------------
// This causes the actor to be rendered. It in turn will render the actor's
// property, texture map and then mapper. If a property hasn't been
......@@ -161,9 +202,8 @@ int vtkActor::RenderOpaqueGeometry(vtkViewport *vp)
this->GetProperty();
}
// is this actor opaque
// Do this check only when not in selection mode
if (this->GetIsOpaque() ||
// Should we render during the opaque pass?
if (this->HasOpaqueGeometry() ||
(ren->GetSelector() && this->Property->GetOpacity() > 0.0))
{
this->Property->Render(this, ren);
......@@ -221,6 +261,8 @@ int vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport *vp)
return 0;
}
this->InTranslucentPass = true;
// make sure we have a property
if (!this->Property)
{
......@@ -228,8 +270,8 @@ int vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport *vp)
this->GetProperty();
}
// is this actor opaque ?
if (!this->GetIsOpaque())
// Should we render during the translucent pass?
if (this->HasTranslucentPolygonalGeometry() && !ren->GetSelector())
{
this->Property->Render(this, ren);
......@@ -273,29 +315,10 @@ int vtkActor::RenderTranslucentPolygonalGeometry(vtkViewport *vp)
renderedSomething = 1;
}
this->InTranslucentPass = false;
return renderedSomething;
}
//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
vtkTypeBool vtkActor::HasTranslucentPolygonalGeometry()
{
if ( ! this->Mapper )
{
return 0;
}
// make sure we have a property
if (!this->Property)
{
// force creation of a property
this->GetProperty();
}
// is this actor opaque ?
return !this->GetIsOpaque();
}
//----------------------------------------------------------------------------
void vtkActor::ReleaseGraphicsResources(vtkWindow *win)
{
......
......@@ -70,10 +70,13 @@ public:
int RenderTranslucentPolygonalGeometry(vtkViewport *viewport) override;
//@}
//@{
/**
* Does this prop have some translucent polygonal geometry?
* Does this prop have some opaque/translucent polygonal geometry?
*/
vtkTypeBool HasTranslucentPolygonalGeometry() override;
vtkTypeBool HasOpaqueGeometry() override;
//@}
/**
* This causes the actor to be rendered. It in turn will render the actor's
......@@ -208,6 +211,12 @@ public:
vtkHardwareSelector *sel,
std::vector<unsigned int> &pixeloffsets) override;
//@{
// Get if we are in the translucent polygonal geometry pass
bool IsRenderingTranslucentPolygonalGeometry() override {
return this->InTranslucentPass; };
//@}
protected:
vtkActor();
~vtkActor() override;
......@@ -216,6 +225,7 @@ protected:
int GetIsOpaque();
bool ForceOpaque;
bool ForceTranslucent;
bool InTranslucentPass;
vtkProperty *Property;
vtkProperty *BackfaceProperty;
......
......@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkCompositePolyDataMapper.h"
#include "vtkActor.h"
#include "vtkCompositeDataIterator.h"
#include "vtkCompositeDataPipeline.h"
#include "vtkCompositeDataSet.h"
......@@ -162,6 +163,13 @@ void vtkCompositePolyDataMapper::Render(vtkRenderer *ren, vtkActor *a)
//Call Render() on each of the PolyDataMappers
for(unsigned int i=0;i<this->Internal->Mappers.size();i++)
{
// skip if we have a mismatch in opaque and translucent
if (a->IsRenderingTranslucentPolygonalGeometry() ==
this->Internal->Mappers[i]->HasOpaqueGeometry())
{
continue;
}
if ( this->ClippingPlanes !=
this->Internal->Mappers[i]->GetClippingPlanes() )
{
......@@ -315,3 +323,45 @@ vtkPolyDataMapper *vtkCompositePolyDataMapper::MakeAMapper()
m->vtkMapper::ShallowCopy( this );
return m;
}
//-----------------------------------------------------------------------------
// look at children
bool vtkCompositePolyDataMapper::HasOpaqueGeometry()
{
//If the PolyDataMappers are not up-to-date then rebuild them
vtkCompositeDataPipeline * executive =
vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive());
if(executive->GetPipelineMTime() > this->InternalMappersBuildTime.GetMTime())
{
this->BuildPolyDataMapper();
}
bool hasOpaque = false;
for(unsigned int i=0; !hasOpaque && i < this->Internal->Mappers.size(); i++)
{
hasOpaque = hasOpaque || this->Internal->Mappers[i]->HasOpaqueGeometry();
}
return hasOpaque;
}
//-----------------------------------------------------------------------------
// look at children
bool vtkCompositePolyDataMapper::HasTranslucentPolygonalGeometry()
{
//If the PolyDataMappers are not up-to-date then rebuild them
vtkCompositeDataPipeline * executive =
vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive());
if(executive->GetPipelineMTime() > this->InternalMappersBuildTime.GetMTime())
{
this->BuildPolyDataMapper();
}
bool hasTrans = false;
for(unsigned int i=0; !hasTrans && i < this->Internal->Mappers.size(); i++)
{
hasTrans = hasTrans || this->Internal->Mappers[i]->HasTranslucentPolygonalGeometry();
}
return hasTrans;
}
......@@ -64,6 +64,16 @@ public:
*/
void ReleaseGraphicsResources(vtkWindow *) override;
//@{
/**
* Some introspection on the type of data the mapper will render
* used by props to determine if they should invoke the mapper
* on a specific rendering pass.
*/
bool HasOpaqueGeometry() override;
bool HasTranslucentPolygonalGeometry() override;
//@}
protected:
vtkCompositePolyDataMapper();
~vtkCompositePolyDataMapper() override;
......
......@@ -173,6 +173,21 @@ int vtkDiscretizableColorTransferFunction::IsOpaque()
return !this->EnableOpacityMapping;
}
int vtkDiscretizableColorTransferFunction::IsOpaque(vtkAbstractArray *scalars,
int colorMode, int component)
{
// use superclass logic?
vtkDataArray *dataArray = vtkArrayDownCast<vtkDataArray>(scalars);
if ((colorMode == VTK_COLOR_MODE_DEFAULT &&
vtkArrayDownCast<vtkUnsignedCharArray>(dataArray) != nullptr) ||
(colorMode == VTK_COLOR_MODE_DIRECT_SCALARS && dataArray))
{
return this->Superclass::IsOpaque(scalars, colorMode, component);
}
// otherwise look at our basic approach
return this->IsOpaque();
}
//-----------------------------------------------------------------------------
void vtkDiscretizableColorTransferFunction::Build()
{
......
......@@ -61,10 +61,14 @@ public:
vtkTypeMacro(vtkDiscretizableColorTransferFunction, vtkColorTransferFunction);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Returns the negation of \a EnableOpacityMapping.
*/
int IsOpaque() override;
int IsOpaque(vtkAbstractArray *scalars,
int colorMode, int component) override;
//@}
/**
* Add colors to use when \a IndexedLookup is true.
......
......@@ -717,17 +717,35 @@ const char *vtkMapper::GetScalarModeAsString()
}
//-----------------------------------------------------------------------------
bool vtkMapper::GetIsOpaque()
bool vtkMapper::HasOpaqueGeometry()
{
// by default we only return true for Opaque or Translucent
// not both.
return !this->HasTranslucentPolygonalGeometry();
}
//-----------------------------------------------------------------------------
bool vtkMapper::HasTranslucentPolygonalGeometry()
{
// scalar visibility?
int cellFlag = 0; // not used
vtkAbstractArray* abstractArray = vtkAbstractMapper::
GetAbstractScalars(this->GetInput(), this->ScalarMode, this->ArrayAccessMode,
this->ArrayId, this->ArrayName, cellFlag);
if ( !this->ScalarVisibility || abstractArray==nullptr)
{ // No scalar colors.
return false;
}
vtkScalarsToColors* lut = this->GetLookupTable();
if (lut)
{
// Ensure that the lookup table is built
lut->Build();
return (lut->IsOpaque() == 1);
return (lut->IsOpaque(abstractArray, this->ColorMode, this->ArrayComponent) == 0);
}
return true;
return false;
}
// anonymous namespace
......
......@@ -464,15 +464,16 @@ public:
int &cellFlag);
//@}
//@{
/**
* Returns if the mapper does not expect to have translucent geometry. This
* may happen when using ColorMode is set to not map scalars i.e. render the
* scalar array directly as colors and the scalar array has opacity i.e. alpha
* component. Default implementation simply returns true. Note that even if
* this method returns true, an actor may treat the geometry as translucent
* since a constant translucency is set on the property, for example.
* Some introspection on the type of data the mapper will render
* used by props to determine if they should invoke the mapper
* on a specific rendering pass.
*/
virtual bool GetIsOpaque();
virtual bool HasOpaqueGeometry();
virtual bool HasTranslucentPolygonalGeometry();
//@}
/**
* WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
......
......@@ -291,6 +291,20 @@ public:
virtual vtkTypeBool HasTranslucentPolygonalGeometry()
{ return 0; }
/**
* WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
* DO NOT USE THESE METHODS OUTSIDE OF THE RENDERING PROCESS
* Does this prop have some opaque geometry?
* This method is called during the rendering process to know if there is
* some opaque geometry. A simple prop that has some
* opaque geometry will return true. A composite prop (like
* vtkAssembly) that has at least one sub-prop that has some opaque
* polygonal geometry will return true.
* Default implementation return true.
*/
virtual vtkTypeBool HasOpaqueGeometry()
{ return 1; }
/**
* WARNING: INTERNAL METHOD - NOT INTENDED FOR GENERAL USE
* Release any graphics resources that are being consumed by this actor.
......@@ -441,6 +455,11 @@ public:
virtual vtkShaderProperty *GetShaderProperty();
//@}
//@{
// Get if we are in the translucent polygonal geometry pass
virtual bool IsRenderingTranslucentPolygonalGeometry() { return false; };
//@}
protected:
vtkProp();
~vtkProp() override;
......
......@@ -45,17 +45,15 @@ public:
vtkTypeMacro(vtkCompositePolyDataMapper2, vtkOpenGLPolyDataMapper);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Returns if the mapper does not expect to have translucent geometry. This
* may happen when using ScalarMode is set to not map scalars i.e. render the
* scalar array directly as colors and the scalar array has opacity i.e. alpha
* component. Note that even if this method returns true, an actor may treat
* the geometry as translucent since a constant translucency is set on the
* property, for example.
* Overridden to use the actual data and ScalarMode to determine if we have
* opaque geometry.
* Some introspection on the type of data the mapper will render
* used by props to determine if they should invoke the mapper
* on a specific rendering pass.
*/
bool GetIsOpaque() override;
bool HasOpaqueGeometry() override;
bool HasTranslucentPolygonalGeometry() override;
//@}
//@{
/**
......@@ -236,8 +234,6 @@ protected:
std::vector<vtkPolyData*> RenderedList;
private:
vtkMTimeType LastOpaqueCheckTime;
bool LastOpaqueCheckValue;
double ColorResult[3];
vtkCompositePolyDataMapper2(const vtkCompositePolyDataMapper2&) = delete;
......
......@@ -6,6 +6,7 @@ public:
vtkPolyData *Data;
unsigned int FlatIndex;
double Opacity;
bool IsOpaque;
bool Visibility;
bool Pickability;
bool OverridesColor;
......
......@@ -61,7 +61,7 @@ void vtkOpenGLActor::Render(vtkRenderer *ren, vtkMapper *mapper)
vtkOpenGLState::ScopedglDepthMask dmsaver(ostate);
// get opacity
bool opaque = (this->GetIsOpaque() != 0);
bool opaque = !this->IsRenderingTranslucentPolygonalGeometry();
if (opaque)
{
ostate->vtkglDepthMask(GL_TRUE);
......
......@@ -1012,13 +1012,14 @@ void vtkOpenGLPointGaussianMapper::ReleaseGraphicsResources(vtkWindow* win)
}
//-----------------------------------------------------------------------------
bool vtkOpenGLPointGaussianMapper::GetIsOpaque()
bool vtkOpenGLPointGaussianMapper::HasTranslucentPolygonalGeometry()
{
// emissive always needs to be opaque
if (this->Emissive)
{
return true;
return false;
}
return this->Superclass::GetIsOpaque();
return this->Superclass::HasTranslucentPolygonalGeometry();
}
//-------------------------------------------------------------------------
......
......@@ -43,9 +43,9 @@ public:
void ReleaseGraphicsResources(vtkWindow *) override;
/**
* Is this mapper opqaue? currently always false.
* Based on emissive setting
*/
bool GetIsOpaque() override;
bool HasTranslucentPolygonalGeometry() override;
/**
* This calls RenderPiece (in a for loop if streaming is necessary).
......
......@@ -3420,48 +3420,6 @@ void vtkOpenGLPolyDataMapper::BuildIBO(
}
}
//-----------------------------------------------------------------------------
bool vtkOpenGLPolyDataMapper::GetIsOpaque()
{
if (this->ScalarVisibility &&
(this->ColorMode == VTK_COLOR_MODE_DEFAULT ||
this->ColorMode == VTK_COLOR_MODE_DIRECT_SCALARS))
{
vtkPolyData* input =
vtkPolyData::SafeDownCast(this->GetInputDataObject(0, 0));
if (input)
{
int cellFlag;
vtkDataArray* scalars = this->GetScalars(input,
this->ScalarMode, this->ArrayAccessMode, this->ArrayId,
this->ArrayName, cellFlag);
if (scalars &&
(scalars->IsA("vtkUnsignedCharArray") ||
this->ColorMode == VTK_COLOR_MODE_DIRECT_SCALARS) &&
(scalars->GetNumberOfComponents() == 4 /*(RGBA)*/ ||
scalars->GetNumberOfComponents() == 2 /*(LuminanceAlpha)*/))
{
int opacityIndex = scalars->GetNumberOfComponents() - 1;
unsigned char opacity = 0;
switch (scalars->GetDataType())
{
vtkTemplateMacro(
vtkScalarsToColors::ColorToUChar(
static_cast<VTK_TT>(scalars->GetRange(opacityIndex)[0]),
&opacity));
}
if (opacity < 255)
{
// If the opacity is 255, despite the fact that the user specified
// RGBA, we know that the Alpha is 100% opaque. So treat as opaque.
return false;
}
}
}
}
return this->Superclass::GetIsOpaque();
}
//----------------------------------------------------------------------------
void vtkOpenGLPolyDataMapper::ShallowCopy(vtkAbstractMapper *mapper)
{
......
......@@ -88,18 +88,6 @@ public:
*/
bool GetSupportsSelection() override { return true; }
/**
* Returns if the mapper does not expect to have translucent geometry. This
* may happen when using ScalarMode is set to not map scalars i.e. render the
* scalar array directly as colors and the scalar array has opacity i.e. alpha
* component. Note that even if this method returns true, an actor may treat
* the geometry as translucent since a constant translucency is set on the
* property, for example.
* Overridden to use the actual data and ScalarMode to determine if we have
* opaque geometry.
*/
bool GetIsOpaque() override;
// used by RenderPiece and functions it calls to reduce
// calls to get the input and allow for rendering of
// other polydata (not the input)
......