How to update Geometry properly

2

I am trying to display a point cloud, consisting of vertices and color with OSG. A static point cloud to display is rather easy with this guide.

But I am not capable of updating such a point cloud. My intention is to create a geometry and attach it to my viewer class once.

This is the mentioned method which is called once in the beginning.

The OSGWidget strongly depends on this OpenGLWidget based approach.

void OSGWidget::attachGeometry(osg::ref_ptr<osg::Geometry> geom)
{
osg::Geode* geode = new osg::Geode;

geom->setDataVariance(osg::Object::DYNAMIC);
geom->setUseDisplayList(false);
geom->setUseVertexBufferObjects(true);
bool addDrawSuccess = geode->addDrawable(geom.get()); // Adding Drawable Shape to the geometry node


if (!addDrawSuccess)
{
    throw "Adding Drawable failed!";
}

{
    osg::StateSet* stateSet = geode->getOrCreateStateSet();
    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
}

float aspectRatio = static_cast<float>(this->width()) / static_cast<float>(this->height());

// Setting up the camera
osg::Camera* camera = new osg::Camera;
camera->setViewport(0, 0, this->width(), this->height());
camera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 1.f)); // Kind of Backgroundcolor, clears the buffer and sets the default color (RGBA)
camera->setProjectionMatrixAsPerspective(30.f, aspectRatio, 1.f, 1000.f); // Create perspective projection
camera->setGraphicsContext(graphicsWindow_); // embed 

osgViewer::View* view = new osgViewer::View;
view->setCamera(camera);                    // Set the defined camera
view->setSceneData(geode);                  // Set the geometry
view->addEventHandler(new osgViewer::StatsHandler);


osgGA::TrackballManipulator* manipulator = new   osgGA::TrackballManipulator;
manipulator->setAllowThrow(false);

view->setCameraManipulator(manipulator);

///////////////////////////////////////////////////
// Set the viewer
//////////////////////////////////////////////////
viewer_->addView(view);
viewer_->setThreadingModel(osgViewer::CompositeViewer::SingleThreaded);
viewer_->realize();

this->setFocusPolicy(Qt::StrongFocus);
this->setMinimumSize(100, 100);

this->setMouseTracking(true);
}

After I have 'attached' the geometry, I am trying to update the geometry like this

void PointCloudViewOSG::processData(DepthDataSet depthData)
{
if (depthData.points()->empty())
{
    return; // empty cloud, cannot do anything
}

const DepthDataSet::IndexPtr::element_type& index = *depthData.index();
const size_t nPixel = depthData.points().get()->points.size();

if (depthData.intensity().isValid() && !index.empty() )
{
    for (int i = 0; i < nPixel; i++)
    {
        float x = depthData.points().get()->points[i].x;
        float y = depthData.points().get()->points[i].y;
        float z = depthData.points().get()->points[i].z;
        m_vertices->push_back(osg::Vec3(x
            , y
            , z));

        // 32 bit integer variable containing the rgb (8 bit per channel) value
        uint32_t rgb_val_;
        memcpy(&rgb_val_, &(depthData.points().get()->points[i].rgb), sizeof(uint32_t));

        uint32_t red, green, blue;
        blue = rgb_val_ & 0x000000ff;

        rgb_val_ = rgb_val_ >> 8;
        green = rgb_val_ & 0x000000ff;

        rgb_val_ = rgb_val_ >> 8;
        red = rgb_val_ & 0x000000ff;

        m_colors->push_back(
            osg::Vec4f((float)red / 255.0f,
            (float)green / 255.0f,
                (float)blue / 255.0f,
                1.0f)
        );
    }

    m_geometry->setVertexArray(m_vertices.get());

    m_geometry->setColorArray(m_colors.get());

    m_geometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX);

    m_geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, m_vertices->size()));      
    }
}

My guess is that the

addPrimitiveSet(...)

Shall not be called every time I update the geometry.

Or can it be the attachment of the geometry, so that I have to reattach it every time?

PointCloudlibrary (PCL) is unfortunately not an alternative since of some incompatibilities with my application.

Update: When I am reattaching the geometry to the OSGWidget class, calling

this->attachGeometry(m_geometry) after

m_geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::POINTS, 0, m_vertices->size()));

I get my point cloud visible, but this procedure is definitely wrong since I am losing way too much performance and the display driver crashes.

c++
opengl
openscenegraph
asked on Stack Overflow Apr 28, 2016 by Daniel R. • edited Apr 28, 2016 by Peter O.

2 Answers

3

You need to set the array and add the primitive set only once, after that you can update the vertices like this:

osg::Vec3Array* vx = static_cast<osg::Vec3Array*>(m_vertices);
for (int i = 0; i < nPixel; i++)
{
   float x, y, z;

   // fill with your data...

   (*vx)[i].set(x, y, z);
}
m_vertices->dirty();

The same goes for colors and other arrays.
As you're using VBO, you don't need to call dirtyDisplayList()
If you need instead to recompure the bounding box of the geometry, call

m_geometry->dirtyBound()

In case the number of points changes between updates, you can push new vertices into the array if its size is too small, and update the PrimitiveSet count like this:

osg::DrawArrays* drawArrays = static_cast<osg::DrawArrays*>(m_geometry->getPrimitiveSet(0));
drawArrays->setCount(nPixel);
drawArrays->dirty();
answered on Stack Overflow Apr 29, 2016 by rickyviking • edited Apr 29, 2016 by rickyviking
0

rickvikings solution works - I only had one issue... (OSG 3.6.1 on OSX)

I had to modify the m_vertices array directly, it would cause OSG to crash if I used the static_cast method above to modify the vertices array: osg::Vec3Array* vx = static_cast(m_vertices); For some reason OSG would not create a buffer object in the vertices array class if using the static_cast approach.

answered on Stack Overflow May 5, 2018 by SteveEng

User contributions licensed under CC BY-SA 3.0