0

我有 [-1024; 范围内的值的 3D 体积;3071]。让我们称之为input。我需要用 OpenGL 以这种方式处理这些值,1 对应于 3071 的值,而 0 映射到 -1024。由于 12 位足以涵盖 4096 个可能值的范围,因此我创建了一个GL_TEXTURE_3D具有内部格式的对象GL_INTENSITY16。在将纹理数据作为值数组上传之前uint16_t,我确实执行了 4 位左移以建立所需的映射,如上所述:

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() );

然后我在这样的步骤中沿 x 方向的一条线对纹理的值进行采样,以始终命中支持点的值,这意味着不需要插值。为了执行采样,将点绘制到帧缓冲区对象,该对象使用纹理对象colorBufferID作为其GL_RGBA16F颜色缓冲区:

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;
}

如前所述,上述函数针对不同的x值执行。获得的强度相对于它们的x位置绘制:

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 );
}

在 CPU 上也是如此,这非常简单。绘图结果如下图所示 - CPU 获得的样本由蓝色曲线显示,通过 OpenGL 获得的样本为红色:

获得数据的绘图 - 蓝色:CPU 获得的样本 - 红色:OpenGL 获得的样本

为什么结果不一样?

4

0 回答 0