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
523 lines
16 KiB
C
3 weeks ago
|
/*=========================================================================
|
||
|
|
||
|
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
|