Commit 41d1dc0e authored by Ken Martin's avatar Ken Martin Committed by Kitware Robot
Browse files

Merge topic 'translucency_fix'

9c70c2b9

 Fixes to translucent Rendering
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Merge-request: !5745
parents 376d47e3 9c70c2b9
Pipeline #141184 failed with stage
in 0 seconds
......@@ -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;
......
......@@ -359,6 +359,7 @@ void vtkCompositeMapperHelper2::DrawIBO(
{
vtkCompositeMapperHelperData *starthdata = it->second;
if (starthdata->Visibility &&
((selecting || starthdata->IsOpaque) != actor->IsRenderingTranslucentPolygonalGeometry()) &&
((selecting && starthdata->Pickability) || !selecting) &&
starthdata->NextIndex[primType] > starthdata->StartIndex[primType])
{
......@@ -1223,9 +1224,7 @@ vtkStandardNewMacro(vtkCompositePolyDataMapper2);
//----------------------------------------------------------------------------
vtkCompositePolyDataMapper2::vtkCompositePolyDataMapper2()
{
this->LastOpaqueCheckTime = 0;
this->CurrentFlatIndex = 0;
this->LastOpaqueCheckValue = true;
this->ColorMissingArraysWithNanColor = false;
}
......@@ -1284,65 +1283,19 @@ void vtkCompositePolyDataMapper2::ComputeBounds()
}
//-----------------------------------------------------------------------------
bool vtkCompositePolyDataMapper2::GetIsOpaque()
// simple tests, the mapper is tolerant of being
// called both on opaque and translucent
bool vtkCompositePolyDataMapper2::HasOpaqueGeometry()
{
vtkCompositeDataSet *input = vtkCompositeDataSet::SafeDownCast(
this->GetInputDataObject(0, 0));
vtkMTimeType lastMTime = std::max(input ? input->GetMTime() : 0, this->GetMTime());
if (lastMTime <= this->LastOpaqueCheckTime)
{
return this->LastOpaqueCheckValue;
}
this->LastOpaqueCheckTime = lastMTime;
if (this->ScalarVisibility && input &&
(this->ColorMode == VTK_COLOR_MODE_DEFAULT ||
this->ColorMode == VTK_COLOR_MODE_DIRECT_SCALARS))
{
using Opts = vtk::CompositeDataSetOptions;
for (vtkDataObject *dObj : vtk::Range(input, Opts::SkipEmptyNodes))
{
vtkPolyData *pd = vtkPolyData::SafeDownCast(dObj);
if (pd)
{
int cellFlag;
vtkDataArray* scalars = this->GetScalars(pd,
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.
this->LastOpaqueCheckValue = false;
return false;
}
}
}
}
}
else if(this->CompositeAttributes &&
this->CompositeAttributes->HasBlockOpacities())
{
this->LastOpaqueCheckValue = false;
return false;
}
return true;
}
this->LastOpaqueCheckValue = this->Superclass::GetIsOpaque();
return this->LastOpaqueCheckValue;
//-----------------------------------------------------------------------------
// simple tests, the mapper is tolerant of being
// called both on opaque and translucent
bool vtkCompositePolyDataMapper2::HasTranslucentPolygonalGeometry()
{
return true;
}
//----------------------------------------------------------------------------
......@@ -1608,11 +1561,15 @@ void vtkCompositePolyDataMapper2::Render(
return;
}
if (!this->Static)
// only rebuild on opaque pass
if (!actor->IsRenderingTranslucentPolygonalGeometry())
{
this->InvokeEvent(vtkCommand::StartEvent,nullptr);