0

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:

Plot of the obtained data - blue: samples obtained by CPU - red: those obtained by OpenGL

Why aren't the results the same?

theV0ID
  • 4,172
  • 9
  • 35
  • 56
  • How exactly do you do this: `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.` – this is a pitfall many of us encountered. – datenwolf Jul 24 '13 at 14:40
  • @datenwolf The exact implementation is given by the last code snippet in my posting. – theV0ID Jul 24 '13 at 14:41
  • 1
    @theV0ID: and it is wrong. YOu are not sampling at texel centers – derhass Jul 24 '13 at 14:43
  • @derhass: can you please give a little more explanation on that? – theV0ID Jul 24 '13 at 14:45
  • 1
    @theV0ID: I explained it in detail here: http://stackoverflow.com/a/5879551/524368 – datenwolf Jul 24 '13 at 14:49
  • @datenwolf: Is this also true if linear interpolation and not `GL_NEAREST` is used? My concern is: Lets say we have a linearly interpolated 1D texture with 2 texels: if the center of the first texel is than at `0.25` and the second at `0.75` - as you state - where are than the values for `<0.25` or `>0.75` obtained from? – theV0ID Jul 24 '13 at 14:58
  • @theV0ID: This is always true, regardless of used interpolation. Texture coordinates 0 and 1 are never on pixel centers, but on the edge of the texture bordering pixels. It depends on the texture clamp/wrap mode, how values are interpolated on the edge. In GL_WRAP mode the topology of the texture interpolator is toroidal, i.e. as you leave the texture to the left you're entering from the right. In GL_CLAMP mode it's extrapolated by constant value of the bordering pixel. – datenwolf Jul 24 '13 at 15:10
  • In case someone else stumbles over this: It's explained quite well here: http://hacksoflife.blogspot.de/2009/12/texture-coordinate-system-for-opengl.html – theV0ID Jul 24 '13 at 15:11

0 Answers0