使用来自 OSG Cookbook 的绘图实例渲染点云数据不起作用

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

我正在使用 OSG 渲染点云。我遵循了标题为 "Rendering point cloud data with draw instancing" 的 OSG 食谱中的示例,该示例展示了如何使用多个实例制作一个点,然后通过纹理将点位置传输到图形卡。然后它使用着色器将点从纹理中拉出并将每个实例移动到正确的位置。渲染的内容似乎有两个问题。

首先,与更直接、有效的渲染方法相比,这些点不在正确的位置。看起来它们是粗略地从零开始缩放的,这是位置上的某种乘法因子。

其次,图像模糊。点通常在正确的位置;应该有大object的地方有很多点。但是,我不知道 object 是什么。使用我的工作(但较慢)渲染方法渲染的数据看起来很清晰。

我已经确认我在两种方法中都有相同的输入数据进入纹理和绘制列表,所以看起来它必须与渲染有关。

这是设置Geometry的代码,几乎是直接从课本上抄来的

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

这样插值器将只从纹理中获取值,而不是从可能是点云另一侧的点的相邻纹理像素中插值它们。解决这两个问题后,该示例如广告所示工作,并且在我的有限测试中似乎更快了一点。