I have a 3D volume of values in the range [-1024; 3071]. Lets call it input
. I need to process those values with OpenGL in such way, that 1 corresponds to a value of 3071 whereas 0 maps to -1024. Since 12 bits are enough to cover a range of 4096 possible values, I create a GL_TEXTURE_3D
object with the internal format GL_INTENSITY16
. Before uploading the texture data as an array of uint16_t
values, I do perform a left-shift by 4 bits in order to establish the required mapping, as described above:
const std::vector< signed short >& inputBuffer = input.buffer();
std::vector< uint16_t > buffer( inputBuffer.size() );
for( unsigned int i = 0; i < inputBuffer .size(); ++i )
{
buffer[ i ]
= static_cast< uint16_t >( ( inputBuffer[ i ] + 1024 ) << 4 );
}
glBindTexture( GL_TEXTURE_3D, volumeTextureID );
glTexImage3D( GL_TEXTURE_3D, 0, GL_INTENSITY16
, size.x, size.y, size.z
, 0, GL_RED, GL_UNSIGNED_SHORT, &buffer.front() );
Then I do sample the values of the texture along a line in x-direction in such steps, that the values supporting points are hit always, meaning that no interpolation is required. In order to perform the sampling, points are drawn to a framebuffer object, which uses the texture object colorBufferID
as its GL_RGBA16F
color buffer:
float gpuSampleAt( float x, float y, float z )
{
bindFramebufferObject();
glBindTexture( GL_TEXTURE_3D, volumeTextureID );
glBegin( GL_POINTS );
glTexCoord3f( x, y, z );
glVertex3f( 0, 0, 0 );
glEnd();
unbindFramebufferObject();
float intensity;
glBindTexture( GL_TEXTURE_2D, colorBufferID );
glGetTexImage( GL_TEXTURE_2D, 0, GL_RED, GL_FLOAT, &intensity );
return intensity * 4095 - 1024;
}
As mentioned, the above function is executed for different x
values. The intensities obtained are plotted in relation to their x
position:
const float ry = y / float( size.y - 1 );
const float rz = z / float( size.z - 1 );
for( unsigned int x = 0; x < size.x; ++x )
{
const float rx = x / float( size.x - 1 );
gpuPlot( x, gpuSampleAt( rx, ry, rz ) );
cpuPlot( x, static_cast< signed short >
( buffer[ x + size.x * y + size.y * size.x * z ] >> 4 ) -1024 );
}
The same is done on the CPU, which is quite straightforward. The results of the plot are shown by the figure below -samples obtained by CPU are shown by the blue curve, those obtained via OpenGL are red colored:
Why aren't the results the same?