Alex Taylor
2018-08-02 16:30:35 UTC
First off, I'm having problems posting to OSG Users with my work email.
Apologies in advance if you receive multiple copies of this same email.
Weâre encountering a puzzling behavior in rendering using
RayTracedTechnique and weâve narrowed it down to what appears to be an
inconsistency in how the TransferFunction passed to osgVolume is defined.
If we use osgVolume::applyTransferFunction
The mapping of our image values to corresponding Vec4 values works
exactly as we would expect. Our TransferFunction is defined as:
osg::ref_ptr<osg::TransferFunction1D> createTransferFunction(const
uint8_T* xfer_table, const bool useIsosurface)
{
osg::TransferFunction1D::ColorMap colorMap;
for (size_t r = 0; r < 256; ++r){
size_t rowOffset = r*4;
float red = static_cast<float>(xfer_table[rowOffset])/255.0f;
float green =
static_cast<float>(xfer_table[rowOffset+1])/255.0f;
float blue = static_cast<float>(xfer_table[rowOffset+2])/255.0f;
float alpha = (useIsosurface) ? 1.0f :
static_cast<float>(xfer_table[rowOffset+3])/255.0f;
colorMap[static_cast<float>(r)/255.0f] =
osg::Vec4(red,green,blue,alpha);
}
osg::TransferFunction1D *transferFunction = new
osg::TransferFunction1D;
transferFunction->assign(colorMap);
osg::ref_ptr<osg::TransferFunction1D> tfSmartPtr = transferFunction;
return tfSmartPtr;
}
Here, xfer_table is a 256x4 array, so we are always defining a
TransferFunction that has exactly as many entries as there are
possible values in our volume.
When we attempt to use the âdirectâ GPU mapping in which we add a
TransferFunction definition to the volume layer:
layer->addProperty(new
osgVolume::TransferFunctionProperty(volumeProperties.transferFunction.get()));
What we see is that the correspondence between the values in our
[0,255] uint8 volume do not seem to map correctly to the
TransferFunction. For example, if we start with a 200x200x200 volume
where the volume contains only two distinct values: [0,255], where
each value is present in a continuous half of the volume:
We see exactly what weâd expect here, where the alpha map is defined on the
right plot and its uniformly 1 for all volume intensity values.
[image: correctImage.jpg]
Now, if we edit the transfer function such that we wouldnât expect to see
any of the 255 valued voxels in the volume, we see things donât render
correctly, you still see the 255 voxels partially.
[image: badImage.jpg]
Again, the exact same transfer function renders as we would expect if we
use osgVolume::applyTransferFunction and render the remapped volume. So, it
seems like maybe the shader used when you do GPU mapping of the transfer
function expects a different convention for the definition of the
TransferFunction map?, but I canât figure out what that convention is.
Apologies for the length of this question and appreciate any advice people
have.
Thanks!
Alex
Apologies in advance if you receive multiple copies of this same email.
Weâre encountering a puzzling behavior in rendering using
RayTracedTechnique and weâve narrowed it down to what appears to be an
inconsistency in how the TransferFunction passed to osgVolume is defined.
If we use osgVolume::applyTransferFunction
The mapping of our image values to corresponding Vec4 values works
exactly as we would expect. Our TransferFunction is defined as:
osg::ref_ptr<osg::TransferFunction1D> createTransferFunction(const
uint8_T* xfer_table, const bool useIsosurface)
{
osg::TransferFunction1D::ColorMap colorMap;
for (size_t r = 0; r < 256; ++r){
size_t rowOffset = r*4;
float red = static_cast<float>(xfer_table[rowOffset])/255.0f;
float green =
static_cast<float>(xfer_table[rowOffset+1])/255.0f;
float blue = static_cast<float>(xfer_table[rowOffset+2])/255.0f;
float alpha = (useIsosurface) ? 1.0f :
static_cast<float>(xfer_table[rowOffset+3])/255.0f;
colorMap[static_cast<float>(r)/255.0f] =
osg::Vec4(red,green,blue,alpha);
}
osg::TransferFunction1D *transferFunction = new
osg::TransferFunction1D;
transferFunction->assign(colorMap);
osg::ref_ptr<osg::TransferFunction1D> tfSmartPtr = transferFunction;
return tfSmartPtr;
}
Here, xfer_table is a 256x4 array, so we are always defining a
TransferFunction that has exactly as many entries as there are
possible values in our volume.
When we attempt to use the âdirectâ GPU mapping in which we add a
TransferFunction definition to the volume layer:
layer->addProperty(new
osgVolume::TransferFunctionProperty(volumeProperties.transferFunction.get()));
What we see is that the correspondence between the values in our
[0,255] uint8 volume do not seem to map correctly to the
TransferFunction. For example, if we start with a 200x200x200 volume
where the volume contains only two distinct values: [0,255], where
each value is present in a continuous half of the volume:
We see exactly what weâd expect here, where the alpha map is defined on the
right plot and its uniformly 1 for all volume intensity values.
[image: correctImage.jpg]
Now, if we edit the transfer function such that we wouldnât expect to see
any of the 255 valued voxels in the volume, we see things donât render
correctly, you still see the 255 voxels partially.
[image: badImage.jpg]
Again, the exact same transfer function renders as we would expect if we
use osgVolume::applyTransferFunction and render the remapped volume. So, it
seems like maybe the shader used when you do GPU mapping of the transfer
function expects a different convention for the definition of the
TransferFunction map?, but I canât figure out what that convention is.
Apologies for the length of this question and appreciate any advice people
have.
Thanks!
Alex