OpenSceneGraph浮动图像

时间:2012-07-31 07:42:49

标签: c++ image floating-point openscenegraph

使用C ++和OSG我正在尝试将浮动纹理上传到我的着色器,但不知何故它似乎不起作用。最后我发布了部分代码。主要问题是如何使用float数组中的数据创建osg :: Image对象。在OpenGL中,所需的代码是

glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE32F_ARB, width, height, 0, 
             GL_LUMINANCE, GL_FLOAT, data);

但在这种情况下我必须使用OSG。

使用

时代码运行正常
Image* image = osgDB::readImageFile("someImage.jpg");  

而不是

image = new Image;  

但我需要上传生成的浮点数据。由于我需要着色器代码中的GL_LUMINANCE32F_ARB数据范围,因此也无法切换到无符号字符数组。

我希望有人可以在这里帮助我,因为谷歌无法帮助我(用谷歌搜索:例如:osg float image)。所以这是我的代码。

using namespace std;
using namespace osg;
//...
float* data = new float[width*height];
fill_n(data, size, 1.0); // << I actually do this for testing purposes
Texture2D* texture = new Texture2D;
Image* image = new Image;
osg::State* state = new osg::State;
Uniform* uniform = new Uniform(Uniform::SAMPLER_2D, "texUniform");
texture->setInternalFormat(GL_LUMINANCE32F_ARB);
texture->setDataVariance(osg::Object::DYNAMIC);
texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP_TO_EDGE);
texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP_TO_EDGE);
if (data == NULL)
  cout << "texdata null" << endl; // << this is not printed
image->setImage(width, height, 1, GL_LUMINANCE32F_ARB,
                GL_LUMINANCE, GL_FLOAT,
                (unsigned char*)data, osg::Image::USE_NEW_DELETE);
if (image->getDataPointer() == NULL)
  cout << "datapointernull" << endl; // << this is printed
if (!image->valid())
  exit(1); //  << here the code exits (hard exit just for testing purposes)
osgDB::writeImageFile(*image, "blah.png");
texture->setInternalFormat(GL_LUMINANCE32F_ARB);
texture->setImage(image);
camera->getOrCreateStateSet()->setTextureAttributeAndModes(4, texture);
state->setActiveTextureUnit(4);
texture->apply(*state);
uniform->set(4);
addProgrammUniform(uniform);

我在网上找到了另一种方法,让osg :: Image创建数据并在之后填充它。但不知何故,这也行不通。我在新的XYZ之后插入了这个;线。

image->setInternalTextureFormat(GL_LUMINANCE32F_ARB);
image->allocateImage(width,height,1,GL_LUMINANCE,GL_FLOAT);
if (image->data() == NULL)
  cout << "null here?!" << endl; // << this is printed.

2 个答案:

答案 0 :(得分:1)

我使用以下(简化)代码来创建和设置浮点纹理:

// Create texture and image
osg::Texture* texture = new osg::Texture2D;
osg::Image* image = new osg::Image();
image->allocateImage(size, size, 1, GL_LUMINANCE, GL_FLOAT);
texture->setInternalFormat(GL_LUMINANCE32F_ARB);
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
texture->setImage(image);

// Set texture to node
osg::StateSet* stateSet = node->getOrCreateStateSet();
stateSet->setTextureAttributeAndModes(TEXTURE_UNIT_NUMBER, texture);

// Set data
float* data = reinterpret_cast<float*>(image->data());
/* ...data processing... */
image->dirty();

您可能想要更改某些参数,但这应该可以为您提供一个开始。我相信在你的情况下TEXTURE_UNIT_NUMBER应该设置为4。

答案 1 :(得分:0)

  

但是我需要上传生成的浮动数据。由于我需要着色器代码中的GL_LUMINANCE32F_ARB数据范围,因此也无法切换到无符号字符数组。

     

osgDB::writeImageFile(*image, "blah.png");

png文件不支持每通道32位数据,因此您不能以这种方式将纹理写入文件。 See the libpng book

  

PNG灰度图像支持任何图像类型的最大像素深度范围。支持1、2、4、8和16位深度,涵盖从简单的黑白扫描到全深度医学和原始天文图像的所有内容。[63]

     

[63]校准的天文图像数据通常存储为32位或64位浮点值,而某些原始数据则表示为32位整数。尽管PNG原则上可以设计一个辅助块来保存适当的转换信息,但PNG都不直接支持这两种格式。但是,动态范围超过16位的数据转换将是一种有损转换-至少要禁止使用PNG的alpha通道或RGB功能。

对于每个通道32位,请检出the OpenEXR format

但是,如果16位浮点数(即半浮点数)足够,那么您可以这样处理:

osg::ref_ptr<osg::Image> heightImage = new osg::Image;
int pixelFormat = GL_LUMINANCE;
int type = GL_HALF_FLOAT;
heightImage->allocateImage(tex_width, tex_height, 1, pixelFormat, type);

现在要实际使用和编写半浮点数,可以使用the GLM library。通过包含<glm/detail/type_half.hpp>可以得到半浮点类型,然后将其称为hdata。 现在,您需要从图像中获取数据指针并将其转换为上述格式:

glm::detail::hdata *data = reinterpret_cast<glm::detail::hdata*>(heightImage->data());

然后您可以像访问一维数组一样访问它,例如

data[currentRow*tex_width+ currentColumn] = glm::detail::toFloat16(3.1415f);

如果您使用osg插件将相同的数据写入bmptif文件,则结果将是错误的。以我为例,我只是将目标图像的左半部分拉伸到整个宽度,而不是灰度,而是采用某种奇怪的颜色编码。