Class SoVolumeSkin
- java.lang.Object
-
- com.openinventor.inventor.Inventor
-
- com.openinventor.inventor.misc.SoBase
-
- com.openinventor.inventor.fields.SoFieldContainer
-
- com.openinventor.inventor.nodes.SoNode
-
- com.openinventor.inventor.nodes.SoShape
-
- com.openinventor.ldm.nodes.SoLdmShape
-
- com.openinventor.volumeviz.nodes.SoVolumeShape
-
- com.openinventor.volumeviz.nodes.SoSlice
-
- com.openinventor.volumeviz.nodes.SoVolumeSkin
-
- All Implemented Interfaces:
SafeDisposable
public class SoVolumeSkin extends SoSlice
Draws a data volume skin. This node draws the "skin" (outer faces) of the data volume defined by the currentSoVolumeData
node. This skin is a set of textured polygons similar to ortho slices.The current
SoVolumeData
node can be specified withdataSetId
. When this field is set to 0, the lastSoVolumeData
node on state is used.For a non-RGBA (scalar valued) volume, each voxel's RGBA value is determined by the current
SoDataRange
andSoTransferFunction
. The current diffuse color and transparency (set, for example, with anSoMaterial
node) modify the appearance of the voxels. This means that, for example, the current transparency can be used as a global alpha value to modulate the overall opacity. For an RGBA volume each voxel's RGBA value comes directly from the volume data.When using an opaque transfer function (no alpha values < 1), this node generates the same image as
SoVolumeRender
, but with much higher performance, because only slices are rendered. A common pattern is to put anSoVolumeRender
node and anSoVolumeSkin
node under anSoSwitch
node. This makes it easy to switch between skin rendering and volume rendering.The
interpolation
field controls how the texture is interpolated.Optionally a bump mapping effect may be applied. Normal vectors are automatically computed from the data value gradient. The
enableBumpMapping
andbumpScale
fields control whether bump mapping is active and the intensity of the effect.The entire skin is pickable, even where it is transparent as a result of the current transfer function. The
SoVolumeSkinDetail
class allows you to get the voxel position and value after picking.Notes:
- Drawing position:
AnSoVolumeSkin
is approximately the same as six ortho slices, but not exactly. The difference is that each face of the skin is drawn at the outer edge of the voxel slice it intersects. So if there is noSoROI
, or the ROI is identical to the volume dimensions, the volume skin faces will be drawn at the limits of the volume extent (bounding box). ForSoOrthoSlice
, the geometry passes through the center of the voxels in the specified slice. So an ortho slice with sliceNumber = 0 will be drawn one-half voxel size (on the slice axis) in from the bounding box of the volume. - Transformation matrices:
The volume size and orientation (like geometry) can be modified by transformation nodes in the scene graph and this in turn modifies the appearance of volume rendering nodes likeSoVolumeSkin
. However the same transformation must be applied to the volume data node and all volume rendering nodes associated with that volume. So effectively any transformation nodes that affect the volume must be placed before the volume data node. - Picking:
The entire skin is pickable, even where it is transparent as a result of the current transfer function. TheSoVolumeSkinDetail
class allows you to get the voxel position and value after picking. - Clipping:
Volume primitives can be clipped using a region of interest (SoROI
), geometry (SoVolumeClippingGroup
) and/or height fields (SoUniformGridClipping
). They are also clipped by OpenGL clipping planes (SoClipPlane
), but we recommend using the VolumeViz clipping nodes instead.
Note that, in general, clipping does not work well withSoVolumeSkin
because the clipped portions of the skin are not "closed", allowing the user to see inside the skin. However theSoROI
node's EXCLUSION_BOX mode does work well and can be used to exclude a sub-region from the skin, forming what is sometimes called a "chair cut". - Dragging:
It is possible to interactively translate and resize a skin that is limited to a subset of the volume (sometimes called a "volume probe"). This is done using an Open Inventor dragger, e.g.SoTabBoxDragger
, to adjust anSoROI
node. This is such a common operation that Open Inventor provides theSoROIManip
node. - Interpolation:
Interpolation is specified using theinterpolation
field. The default (LINEAR) does bi-linear interpolation between voxel values. The NEAREST value can be used to display individual voxels. For best image quality we recommend using the TRILINEAR or MULTISAMPLE_12 value. - Material:
The color of each voxel is modulated by the current diffuse color in the traversal state. The default diffuse color is 0.8,0.8,0.8. This results in full intensity values in the color map being displayed as 80% intensity. Therefore we recommend adding anSoMaterial
node before the skin and setting its diffuseColor field to full white (1,1,1). - Transparency:
Typically the color map (SoTransferFunction
) used for volume rendering (SoVolumeRender
) assigns transparency (alpha < 1) to some voxel values. If you want to use the same color map for skin rendering, but render the slice completely opaque, set thealphaUse
field to ALPHA_OPAQUE. This overrides the alpha values in the color map (or an RGBA volume). However it does not affect transparency assigned using anSoMaterial
node. - Voxel edges:
The edges of the voxels can also be rendered. See options in theSoVolumeRenderingQuality
node. - Custom shaders:
The currentSoVolumeShader
node, if any, allows custom shaders to be defined for special computation or rendering effects, including blending multiple volumes. - Composition with Multiple Data:
It is possible to compose datasets that have different dimensions, tile sizes and transformations.
In order to help fetch the correct data values in custom shaders, texture coordinates conversion functions are provided in the VolumeViz/vvizStructure.h shader include.
For instance,vec3 VVizTextureToTextureVec(in VVizDataSetId datasetSrc, in VVizDataSetId datasetDst, in vec3 texCoord);
The conversion is based solely on the transformations applied to each dataset, which are defined by their model matrix and their extent.
Please note that the model matrix of a dataset is defined by to theSoTransformation
nodes that are placed before theSoDataSet
node in the order of the traversal. - Large Slice mode:
When the "large slice" mode is enabled (seeSoSlice.largeSliceSupport
), if all the required full resolution tiles have already been loaded, then the slice data is taken from LDM system memory cache as usual. But if some required tiles are not currently in memory, the required slice data will be loaded directly from the volume reader without loading the complete tiles. This reduces disk I/O and reduces the amount of system memory required to display the slice at full resolution, so larger (or more) slices can be displayed. The required tiles are then scheduled to be loaded asynchronously in case adjacent slices are displayed later. For example, loading a 1024x1024SoOrthoSlice
from an 8-bit dataset with 128x128x128 tiles would normally require loading 1024x1024x128 bytes of data (as complete tiles). With largeSliceSupport enabled, only 1024x1024 bytes (maximum) of data need to be loaded (in the worst case where no high resolution data is currently in memory). - Performance:
- Tile size:
For backward compatibility, the default tile size is still only 64. This is quite small for modern CPU/GPU hardware. The smaller the tile size, the larger the total number of tiles that must be managed by VolumeViz. This overhead can be significant, especially for operations that require reloading the data textures on the GPU, for example, changing the data range (SoDataRange
). For smaller volumes, like 512^3, it can be efficient to set the tile size large enough to contain the entire volume. For very large volumes, larger tile sizes are efficient forSoVolumeRender
but somewhat inefficient for slice rendering because complete tiles must be loaded even though the slice only uses part of the data. Applications should experiment.
For volumes stored in LDM file format, the tile size must be specified when the volume is converted to LDM (seeSoConverter
and the "-t" option). For other data data formats the tile size can be specified using theSoVolumeData
node's ldmResourceParameters field, but only after setting the filename field or calling the setReader() method.
- LDM_USE_IN_MEM_COMPRESSION
VolumeViz always manages data as "tiles", regardless of the data format. In many cases VolumeViz must create (or uncompress) the tiles at run time. These cases include in-memory volumes, any volume reader that does not implement the readTile() method (this includes all built-in formats except LDM, e.g. DICOM, SEGY, ...) and compressed LDM format files. If this variable is true (the default), VolumeViz only keeps a small cache of created/uncompressed tiles in CPU memory. If a tile's data is needed and that tile is not in the cache, the tile must be recreated. This overhead can be significant, especially for operations that require recreating all the data textures on the GPU, for example changing the data range (SoDataRange
). We recommend setting this variable to false (seeSoPreferences
) unless saving CPU memory is critical. - Compressed textures:
For performance reasons,SoVolumeSkin
accumulates small textures into a bigger one. When using compressed RGBA textures (viaSoDataSet
's field useCompressedTexture), this optimization cannot be done. If you want to favor performance rather than memory usage, you should disable compression (enabled by default if supported by the graphic card)
- Tile size:
EXAMPLE For simple data sets, a basic VolumeViz rendering could be achieved with only a few nodes: minimally an
SoVolumeData
node to identify the data set and one rendering node. However most data sets need at least some of the additional nodes shown here in order to get a correct and useful rendering. Most applications will need additional nodes to take advantage of region of interest, interaction, clipping and other VolumeViz features. Please consider the code shown here as simply a guideline and a starting point for exploring the many powerful features available in Open Inventor.Note that some of the property nodes (data, material, color map, etc) will typically be shared by multiple rendering nodes. In other words the volume usually only needs to be loaded once, using a single
SoVolumeData
node, then multiple slices and/or regions can be rendered using that data node.Also note that this example is for a data volume, where each voxel can be considered a discrete sample from a continuous data field and interpolation should be used to compute values between voxel centers. If you are rendering a label volume, then each voxel is an "id" assigning that voxel to a specific material, object, etc. In this case, set the interpolation field to NEAREST to disable interpolation.
// Default setting can be a performance bottleneck SoPreferences.setValue( "LDM_USE_IN_MEM_COMPRESSION", "0" ); // Default setting can be a performance bottleneck SoPreferences.setValue( "LDM_USE_IN_MEM_COMPRESSION", "0" ); // Keep volume viz separate from geometry SoSeparator volSep = new SoSeparator(); root.addChild(volSep); // Load volume data SoVolumeData volData = new SoVolumeData(); volData.fileName.setValue( "$OIVJHOME/data/VolumeViz/Colt.vol" ); volData.ldmResourceParameters.getValue().tileDimension.setValue(128,128,128); volSep.addChild( volData ); // Set range of data values to visualize. // Not required for 8-bit voxels, critical for larger data types. // The getMinMax() call may be expensive for non-LDM file formats. SoDataRange volRange = new SoDataRange(); if (volData.getDatumSize() > 1) { double[] minmax; minmax = volData.getDoubleMinMax(); volRange.min.setValue( minmax[0] ); volRange.max.setValue( minmax[1] ); } volSep.addChild( volRange ); // Load opaque seismic color map SoTransferFunction volTF = new SoTransferFunction(); volTF.predefColorMap.setValue( SoTransferFunction.PredefColorMaps.BLUE_WHITE_RED ); volSep.addChild( volTF ); // Display volume at full intensity SoMaterial volMat = new SoMaterial(); volMat.diffuseColor.setValue( 1, 1, 1 ); volSep.addChild( volMat ); // Remove tile boundary artifacts while moving. SoVolumeShader volShader = new SoVolumeShader(); volShader.interpolateOnMove.setValue( true ); volSep.addChild( volShader ); // Display volume skin SoVolumeSkin volSkin = new SoVolumeSkin(); volSep.addChild( volSkin ); File format/default:
VolumeSkin {
dataSetId 0 interpolation LINEAR alphaUse ALPHA_AS_IS useRGBA false enableBumpMapping false bumpScale 1.0 faceMode FRONT Action behavior:
SoGLRenderAction
Draws a volume-rendered image based on currentSoVolumeData
.SoGetBoundingBoxAction
Computes the bounding box that encloses the volume.- See Also:
SoVolumeData
,SoTransferFunction
,SoROI
,SoVolumeShader
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
SoVolumeSkin.FaceModes
Use this enum with thefaceMode
field.-
Nested classes/interfaces inherited from class com.openinventor.volumeviz.nodes.SoSlice
SoSlice.AlphaUses
-
Nested classes/interfaces inherited from class com.openinventor.volumeviz.nodes.SoVolumeShape
SoVolumeShape.Compositions, SoVolumeShape.Interpolations
-
Nested classes/interfaces inherited from class com.openinventor.inventor.nodes.SoShape
SoShape.ShapeTypes
-
Nested classes/interfaces inherited from class com.openinventor.inventor.nodes.SoNode
SoNode.RenderModes
-
Nested classes/interfaces inherited from class com.openinventor.inventor.Inventor
Inventor.ConstructorCommand
-
-
Field Summary
Fields Modifier and Type Field Description SoSFInt32
dataSetId
Specifies theSoVolumeData
node to use.SoSFEnum<SoVolumeSkin.FaceModes>
faceMode
Display front (facing the camera) faces or back faces.-
Fields inherited from class com.openinventor.volumeviz.nodes.SoSlice
alphaUse, alternateRep, bumpScale, enableBumpMapping, largeSliceSupport, useRGBA
-
Fields inherited from class com.openinventor.volumeviz.nodes.SoVolumeShape
composition, interpolation
-
Fields inherited from class com.openinventor.inventor.nodes.SoShape
boundingBoxIgnoring
-
Fields inherited from class com.openinventor.inventor.Inventor
VERBOSE_LEVEL, ZeroHandle
-
-
Constructor Summary
Constructors Constructor Description SoVolumeSkin()
Constructor.
-
Method Summary
-
Methods inherited from class com.openinventor.inventor.nodes.SoShape
getShapeType, isPrimitiveRestartAvailable, isPrimitiveRestartAvailable
-
Methods inherited from class com.openinventor.inventor.nodes.SoNode
affectsState, callback, copy, copy, distribute, doAction, getAlternateRep, getBoundingBox, getByName, getMatrix, getPrimitiveCount, getRenderEngineMode, getRenderUnitID, GLRender, GLRenderBelowPath, GLRenderInPath, GLRenderOffPath, grabEventsCleanup, grabEventsSetup, handleEvent, isBoundingBoxIgnoring, isOverride, pick, rayPick, search, setOverride, touch, write
-
Methods inherited from class com.openinventor.inventor.fields.SoFieldContainer
copyFieldValues, copyFieldValues, enableNotify, fieldsAreEqual, get, getAllFields, getEventIn, getEventOut, getField, getFieldName, hasDefaultValues, isNotifyEnabled, set, setToDefaults
-
Methods inherited from class com.openinventor.inventor.misc.SoBase
dispose, getName, isDisposable, isSynchronizable, setName, setSynchronizable
-
Methods inherited from class com.openinventor.inventor.Inventor
getNativeResourceHandle
-
-
-
-
Field Detail
-
dataSetId
public final SoSFInt32 dataSetId
Specifies theSoVolumeData
node to use. This is useful when datasets of different dimensions are present in the scene graph. Please seeSoMultiDataSeparator
for more details.When set to 0, the last
SoVolumeData
node on state is used. Default is 0.- Since:
- Open Inventor 10.11.0
-
faceMode
public final SoSFEnum<SoVolumeSkin.FaceModes> faceMode
Display front (facing the camera) faces or back faces. . Default is FRONT. Displaying only front (or back) faces reduces the amount of data that must be loaded and reduces the rendering time.- Since:
- Open Inventor 8.1
-
-