我有 [-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 获得的样本为红色:
为什么结果不一样?