You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

523 lines
16 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkHardwareSelector.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/*
* @class vtkHardwareSelector
* @brief manager for OpenGL-based selection.
*
* vtkHardwareSelector is a helper that orchestrates color buffer based
* selection. This relies on OpenGL.
* vtkHardwareSelector can be used to select visible cells or points within a
* given rectangle of the RenderWindow.
* To use it, call in order:
* \li SetRenderer() - to select the renderer in which we
* want to select the cells/points.
* \li SetArea() - to set the rectangular region in the render window to select
* in.
* \li SetFieldAssociation() - to select the attribute to select i.e.
* cells/points etc.
* \li Finally, call Select().
* Select will cause the attached vtkRenderer to render in a special color mode,
* where each cell/point is given it own color so that later inspection of the
* Rendered Pixels can determine what cells are visible. Select() returns a new
* vtkSelection instance with the cells/points selected.
*
* Limitations:
* Antialiasing will break this class. If your graphics card settings force
* their use this class will return invalid results.
*
* Only Opaque geometry in Actors is selected from. Assemblies and LODMappers
* are not currently supported.
*
* During selection, visible datasets that can not be selected from are
* temporarily hidden so as not to produce invalid indices from their colors.
*
*
* The basic approach this class uses is to invoke render multiple times
* (passes) and have the mappers render pass specific information into
* the color buffer. For example during the ACTOR_PASS a mapper is
* supposed to render it's actor's id into the color buffer as a RGB
* value where R is the lower 8 bits, G is the next 8, etc. Giving us 24
* bits of unsigned int range.
*
* The same concept applies to the COMPOSITE_INDEX_PASS and the point and
* cell ID passes. As points and cells can easily exceed the 24 bit range
* of the color buffer we break them into two 24 bit passes for a total
* of 48 bits of range.
*
* During each pass the mappers render their data into the color buffer,
* the hardware selector grabs that buffer and then invokes
* ProcessSelectorPixelBuffer on all of the hit props. Giving them, and
* their mappers, a chance to modify the pixel buffer.
*
* Most mappers use this ProcessSelectorPixelBuffers pass to take when
* they rendered into the color buffer and convert it into what the
* hardware selector is expecting. This is because in some cases it is
* far easier and faster to render something else, such as
* gl_PrimitiveID or gl_VertexID and then in the processing convert those
* values to the appropriate VTK values.
*
* NOTE: The goal is for mappers to support hardware selection without
* having to rebuild any of their VBO/IBOs to maintain fast picking
* performance.
*
* NOTE: This class has a complex interaction with parallel compositing
* techniques such as IceT that are used on supercomputers. In those
* cases the local nodes render each pass, process it, send it to icet
* which composits it, and then must copy the result back to the hardware
* selector. Be aware of these interactions if you work on this class.
*
* NOTE: many mappers support remapping arrays from their local value to
* some other provided value. For example ParaView when creating a
* polydata from an unstructured grid will create point and cell data
* arrays on the polydata that may the polydata point and cell IDs back
* to the original unstructured grid's point and cell IDs. The hardware
* selection process honors those arrays and will provide the original
* unstructured grid point and cell ID when a selection is made.
* Likewise there are process and composite arrays that most mappers
* support that allow for parallel data generation, delivery, and local
* rendering while preserving the original process and composite values
* from when the data was distributed. Be aware the process array is a
* point data while the composite array is a cell data.
*
* TODO: This whole selection process could be nicely encapsulated as a
* RenderPass that internally renders multiple times with different
* settings. That would be my suggestion for the future.
*
* TODO: The pick method build into renderer could use the ACTOR pass of
* this class to do it's work eliminating some confusion and duplicate
* code paths.
*
* TODO: I am not sure where the composite array indirection is used.
*
*
* @sa
* vtkOpenGLHardwareSelector
*/
#ifndef vtkHardwareSelector_h
#define vtkHardwareSelector_h
#include "vtkObject.h"
#include "vtkRenderingCoreModule.h" // For export macro
#include <string> // for std::string
class vtkRenderer;
class vtkRenderWindow;
class vtkSelection;
class vtkProp;
class vtkTextureObject;
class VTKRENDERINGCORE_EXPORT vtkHardwareSelector : public vtkObject
{
public:
//@{
/**
* Struct used to return information about a pixel location.
*/
struct PixelInformation
{
bool Valid;
int ProcessID;
int PropID;
vtkProp* Prop;
unsigned int CompositeID;
vtkIdType AttributeID;
PixelInformation()
: Valid(false)
, ProcessID(-1)
, PropID(-1)
, Prop(nullptr)
, CompositeID(0)
, AttributeID(-1)
{
}
};
//@}
public:
static vtkHardwareSelector* New();
vtkTypeMacro(vtkHardwareSelector, vtkObject);
void PrintSelf(ostream& os, vtkIndent indent) override;
//@{
/**
* Get/Set the renderer to perform the selection on.
*/
virtual void SetRenderer(vtkRenderer*);
vtkGetObjectMacro(Renderer, vtkRenderer);
//@}
//@{
/**
* Get/Set the area to select as (xmin, ymin, xmax, ymax).
*/
vtkSetVector4Macro(Area, unsigned int);
vtkGetVector4Macro(Area, unsigned int);
//@}
//@{
/**
* Set the field type to select. Valid values are
* \li vtkDataObject::FIELD_ASSOCIATION_POINTS
* \li vtkDataObject::FIELD_ASSOCIATION_CELLS
* \li vtkDataObject::FIELD_ASSOCIATION_VERTICES
* \li vtkDataObject::FIELD_ASSOCIATION_EDGES
* \li vtkDataObject::FIELD_ASSOCIATION_ROWS
* Currently only FIELD_ASSOCIATION_POINTS and FIELD_ASSOCIATION_CELLS are
* supported.
*/
vtkSetMacro(FieldAssociation, int);
vtkGetMacro(FieldAssociation, int);
//@}
//@{
/**
* In some parallel rendering setups, the process id for elements must be
* obtained from the data itself, rather than the rendering process' id. In
* that case, set this flag to ON (default OFF).
*/
vtkSetMacro(UseProcessIdFromData, bool);
vtkGetMacro(UseProcessIdFromData, bool);
//@}
/**
* Perform the selection. Returns a new instance of vtkSelection containing
* the selection on success.
*/
vtkSelection* Select();
//@{
/**
* It is possible to use the vtkHardwareSelector for a custom picking. (Look
* at vtkScenePicker). In that case instead of Select() on can use
* CaptureBuffers() to render the selection buffers and then get information
* about pixel locations suing GetPixelInformation(). Use ClearBuffers() to
* clear buffers after one's done with the scene.
* The optional final parameter maxDist will look for a cell within the specified
* number of pixels from display_position. When using the overload with the
* optional \c selected_position argument, selected_position is filled with
* the position for which the PixelInformation is being returned. This is
* useful when maxDist > 0 to determine which position's pixel information is
* was returned.
*/
virtual bool CaptureBuffers();
PixelInformation GetPixelInformation(const unsigned int display_position[2])
{
return this->GetPixelInformation(display_position, 0);
}
PixelInformation GetPixelInformation(const unsigned int display_position[2], int maxDist)
{
unsigned int temp[2];
return this->GetPixelInformation(display_position, maxDist, temp);
}
PixelInformation GetPixelInformation(
const unsigned int display_position[2], int maxDist, unsigned int selected_position[2]);
void ClearBuffers() { this->ReleasePixBuffers(); }
// raw is before processing
unsigned char* GetRawPixelBuffer(int passNo) { return this->RawPixBuffer[passNo]; }
unsigned char* GetPixelBuffer(int passNo) { return this->PixBuffer[passNo]; }
//@}
/**
* Called by any vtkMapper or vtkProp subclass to render a composite-index.
* Currently indices >= 0xffffff are not supported.
*/
virtual void RenderCompositeIndex(unsigned int index);
//@{
/**
* Called by any vtkMapper or vtkProp subclass to indicate the
* maximum cell or point attribute ID it uses. These values are
* used for determining if the POINT_ID_HIGH or CELL_ID_HIGH
* passes are required.
*/
virtual void UpdateMaximumCellId(vtkIdType attribid);
virtual void UpdateMaximumPointId(vtkIdType attribid);
//@}
/**
* Called by any vtkMapper or subclass to render process id. This has any
* effect when this->UseProcessIdFromData is true.
*/
virtual void RenderProcessId(unsigned int processid);
/**
* Called by vtkRenderer to render the selection pass.
* Returns the number of props rendered.
*/
int Render(vtkRenderer* renderer, vtkProp** propArray, int propArrayCount);
//@{
/**
* Get/Set to only do the actor pass. If true all other passes will be
* skipped resulting in a faster pick.
*/
vtkGetMacro(ActorPassOnly, bool);
vtkSetMacro(ActorPassOnly, bool);
//@}
//@{
/**
* Get/Set to capture the zvalue. If true the closest zvalue is
* stored for each prop that is in the selection. ZValue in this
* case is the value from the zbuffer which can be used in
* coordinate conversions
*/
vtkGetMacro(CaptureZValues, bool);
vtkSetMacro(CaptureZValues, bool);
//@}
//@{
/**
* Called by the mapper before and after rendering each prop.
*/
virtual void BeginRenderProp();
virtual void EndRenderProp();
//@}
//@{
/**
* Get/Set the process id. If process id < 0 (default -1), then the
* PROCESS_PASS is not rendered.
*/
vtkSetMacro(ProcessID, int);
vtkGetMacro(ProcessID, int);
//@}
//@{
/**
* Get/Set the color to be used by the prop when drawing
*/
vtkGetVector3Macro(PropColorValue, float);
vtkSetVector3Macro(PropColorValue, float);
void SetPropColorValue(vtkIdType val);
//@}
//@{
/**
* Get the current pass number.
*/
vtkGetMacro(CurrentPass, int);
//@}
/**
* Generates the vtkSelection from pixel buffers.
* Requires that CaptureBuffers() has already been called.
* Optionally you may pass a screen region (xmin, ymin, xmax, ymax)
* to generate a selection from. The region must be a subregion
* of the region specified by SetArea(), otherwise it will be
* clipped to that region.
*/
virtual vtkSelection* GenerateSelection() { return GenerateSelection(this->Area); }
virtual vtkSelection* GenerateSelection(unsigned int r[4])
{
return GenerateSelection(r[0], r[1], r[2], r[3]);
}
virtual vtkSelection* GenerateSelection(
unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2);
/**
* Generates the vtkSelection from pixel buffers.
* Same as GenerateSelection, except this one use a polygon, instead
* of a rectangle region, and select elements inside the polygon.
* NOTE: The CaptureBuffers() needs to be called first.
*/
virtual vtkSelection* GeneratePolygonSelection(int* polygonPoints, vtkIdType count);
/**
* returns the prop associated with a ID. This is valid only until
* ReleasePixBuffers() gets called.
*/
vtkProp* GetPropFromID(int id);
// it is very critical that these passes happen in the right order
// this is because of two complexities
//
// Compositing engines such as iceT send each pass as it
// renders. This means
//
// Mappers use point Ids or cell Id to update the process
// and composite ids. So the point and cell id passes
// have to happen before the last process and compoite
// passes respectively
//
//
enum PassTypes
{
// always must be first so that the prop IDs are set
ACTOR_PASS,
// must always be second for composite mapper
COMPOSITE_INDEX_PASS,
POINT_ID_LOW24,
POINT_ID_HIGH24, // if needed
PROCESS_PASS, // best to be after point id pass
CELL_ID_LOW24,
CELL_ID_HIGH24, // if needed
MAX_KNOWN_PASS = CELL_ID_HIGH24,
MIN_KNOWN_PASS = ACTOR_PASS
};
/**
* Convert a PassTypes enum value to a human readable string.
*/
std::string PassTypeToString(PassTypes type);
static void Convert(vtkIdType id, float tcoord[3])
{
tcoord[0] = static_cast<float>((id & 0xff) / 255.0);
tcoord[1] = static_cast<float>(((id & 0xff00) >> 8) / 255.0);
tcoord[2] = static_cast<float>(((id & 0xff0000) >> 16) / 255.0);
}
// grab the pixel buffer and save it
// typically called internally
virtual void SavePixelBuffer(int passNo);
protected:
vtkHardwareSelector();
~vtkHardwareSelector() override;
// Used to notify subclasses when a capture pass is occurring.
virtual void PreCapturePass(int pass) { (void)pass; }
virtual void PostCapturePass(int pass) { (void)pass; }
// Called internally before and after each prop is rendered
// for device specific configuration/preparation etc.
virtual void BeginRenderProp(vtkRenderWindow*) = 0;
virtual void EndRenderProp(vtkRenderWindow*) = 0;
double GetZValue(int propid);
int Convert(unsigned long offset, unsigned char* pb)
{
if (!pb)
{
return 0;
}
offset = offset * 3;
unsigned char rgb[3];
rgb[0] = pb[offset];
rgb[1] = pb[offset + 1];
rgb[2] = pb[offset + 2];
int val = 0;
val |= rgb[2];
val = val << 8;
val |= rgb[1];
val = val << 8;
val |= rgb[0];
return val;
}
//@{
/**
* \c pos must be relative to the lower-left corner of this->Area.
*/
int Convert(unsigned int pos[2], unsigned char* pb) { return this->Convert(pos[0], pos[1], pb); }
int Convert(int xx, int yy, unsigned char* pb)
{
if (!pb)
{
return 0;
}
int offset = (yy * static_cast<int>(this->Area[2] - this->Area[0] + 1) + xx) * 3;
unsigned char rgb[3];
rgb[0] = pb[offset];
rgb[1] = pb[offset + 1];
rgb[2] = pb[offset + 2];
int val = 0;
val |= rgb[2];
val = val << 8;
val |= rgb[1];
val = val << 8;
val |= rgb[0];
return val;
}
//@}
vtkIdType GetID(int low24, int mid24, int high16)
{
vtkIdType val = 0;
val |= high16;
val = val << 24;
val |= mid24;
val = val << 24;
val |= low24;
return val;
}
/**
* Returns is the pass indicated is needed.
*/
virtual bool PassRequired(int pass);
/**
* After the ACTOR_PASS this return true or false depending upon whether the
* prop was hit in the ACTOR_PASS. This makes it possible to skip props that
* are not involved in the selection after the first pass.
*/
bool IsPropHit(int propid);
/**
* Return a unique ID for the prop.
*/
virtual int GetPropID(int idx, vtkProp* vtkNotUsed(prop)) { return idx; }
virtual void BeginSelection();
virtual void EndSelection();
virtual void ProcessPixelBuffers();
void BuildPropHitList(unsigned char* rgbData);
//@{
/**
* Clears all pixel buffers.
*/
void ReleasePixBuffers();
vtkRenderer* Renderer;
unsigned int Area[4];
int FieldAssociation;
bool UseProcessIdFromData;
vtkIdType MaximumPointId;
vtkIdType MaximumCellId;
//@}
// At most 10 passes.
unsigned char* PixBuffer[10];
unsigned char* RawPixBuffer[10];
int ProcessID;
int CurrentPass;
int Iteration;
int InPropRender;
int PropID;
float PropColorValue[3];
bool ActorPassOnly;
bool CaptureZValues;
private:
vtkHardwareSelector(const vtkHardwareSelector&) = delete;
void operator=(const vtkHardwareSelector&) = delete;
class vtkInternals;
vtkInternals* Internals;
};
#endif