用OSG Cookbook中的draw实例渲染点云数据不工作

Rendering point cloud data with draw instancing from OSG Cookbook not working

本文关键字:数据 工作 Cookbook OSG 中的 draw 实例      更新时间:2023-10-16

我正在使用OSG渲染点云。我遵循OSG烹饪书中的例子"用绘制实例渲染点云数据",展示了如何用许多实例制作一个点,然后通过纹理将点位置转移到显卡上。然后使用着色器将点从纹理中拉出,并将每个实例移动到正确的位置。渲染的内容似乎有两个问题。

首先,与更直接的渲染方法相比,这些点不在正确的位置。看起来它们从0开始大致缩放错了,某种位置上的乘法因子。

第二,图像模糊。点数通常位于正确的位置;在应该放一个大物体的地方有很多点。但是,我看不出是什么东西。用我的工作(但较慢)渲染方法渲染的数据看起来很清晰。

我已经验证,我有相同的输入数据进入纹理和绘制列表在这两种方法,所以它似乎必须与渲染的东西。

下面是设置几何的代码,它几乎是直接从课本中复制的。

osg::Geometry* geo = new osg::Geometry;
osg::ref_ptr<osg::Image> img = new osg::Image;
img->allocateImage(w,h, 1, GL_RGBA, GL_FLOAT);
osg::BoundingBox box;
float* data = (float*)img->data();
for (unsigned long int k=0; k<NPoints; k++)
{
    *(data++) = cloud->x[k];
    *(data++) = cloud->y[k];
    *(data++) = cloud->z[k];
    *(data++) = cloud->meta[0][k];
    box.expandBy(cloud->x[k],cloud->y[k],cloud->z[k]);
}
geo->setUseDisplayList(false);
geo->setUseVertexBufferObjects(true);
geo->setVertexArray( new osg::Vec3Array(1));
geo->addPrimitiveSet( new osg::DrawArrays(GL_POINTS, 0, 1, stop) );
geo->setInitialBound(box);
osg::ref_ptr<osg::Texture2D> tex = new osg::Texture2D;
tex->setImage( img);
tex->setInternalFormat( GL_RGBA32F_ARB );
tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);

这里是着色器代码。

void main () {
    float row;
    row = float(gl_InstanceID) / float(width);
    vec2 uv = vec2( fract(row), floor(row) / float(height) );
    vec4 texValue = texture2D(defaultTex,uv);
    vec4 pos = gl_Vertex + vec4(texValue.xyz, 1.0);
    gl_Position = gl_ModelViewProjectionMatrix * pos;
}

经过大量的实验,我发现来自OSG Cookbook的示例代码有一些问题。

比例问题(第一个问题)是在着色器。

vec4 pos = gl_Vertex + vec4(texValue.xyz, 1.0);
应该

vec4 pos = gl_Vertex + vec4(texValue.xyz, 0.0);

这是因为gl_Vertex是一个3向量,有一个额外的1元素来辅助矩阵变换。这个元素应该总是1。本例创建了另一个3+1向量,并将其添加到gl_Vertex,使其为2。用零代替1,比例问题就解决了。

模糊(第二个问题)是由纹理插值引起的。

tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);

必须是

tex->setFilter( osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
tex->setFilter( osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);

,这样插值器将只从纹理中获取值,而不是从相邻的纹理像素(可能是点云另一侧的点)中进行插值。在解决了这两个问题之后,这个例子就像广告中宣传的那样工作了,在我有限的测试中似乎快了一点。