[vtkusers] realtime terrain map, memory allocation/leak questions

Robert Dean bob.dean at gmail.com
Sun Sep 2 19:40:35 EDT 2012


Hello,

I have a voxel type terrain/height map updated at 1Hz. At first I tried
using glyphs for the cells, which (un-surprisingly) turned out to be too
slow. I re-wrote it today to use cells of triangle strips. I have been
hitting my head on the wall with memory leaks, and after scouring the c++
examples I am almost to the point of scrapping everything and running back
to direct openGL.

As the number of cells, points, etc are constant, I thought it would be
possible to declare things as vtkSmartPointer<> kept as class members. This
works for the points data (points,normals, colors), but if I try it with
anything else (such as vtkcellarray, vtkPolyDataMapper, or vtkPolyData), i
see huge memory leaks. the leak from polydata was really weird

Would someone please look at the code below and tell me what i'm missing?
 If i understand the book and tutorials, i should be able to just create
everything once and then update the data arrays... is there some sort of a
cleanup method I should be calling on each update? (also recommendations on
how to use less memory would be appreciated)

for reference a "MapHandle" is a boost::shared_ptr<Map>, where Map is a
vector of Cells. Map also has convenience methods to convert from iterators
to/from x.y.z points.

 class MapActor
            {
            public:

                MapActor();
                ~MapActor();

                void updateMap(MapHandle handle, ColorMap &objectColors,
bool heightColor = false);

                vtkActor * actorPointer() { return actor; };

            private:

                rframe::Timer updateTimer;

                vtkSmartPointer<vtkPoints> points;
                vtkSmartPointer<vtkFloatArray> normals;
                vtkSmartPointer<vtkUnsignedCharArray> colors;
                vtkSmartPointer<vtkPolyData> polydata;
                vtkSmartPointer<vtkCellArray> celldata;
                vtkSmartPointer<vtkPolyDataMapper> mapper;
                vtkSmartPointer<vtkActor> actor;
                vtkSmartPointer<vtkLookupTable> heightLut;

                MapHandle mapHandle;
            };


MapActor::MapActor()
{
    polydata = vtkSmartPointer<vtkPolyData>::New();

    // create empty polydata for now
    polydata = vtkSmartPointer<vtkPolyData>::New();

    heightLut = vtkSmartPointer<vtkLookupTable>::New();
    heightLut->SetHueRange(0.6667,0.0);
    //   heightLut->SetTableRange(-3,10);
    heightLut->SetTableRange(-1,1);
    heightLut->Build();

    actor = vtkSmartPointer<vtkActor>::New();
}


MapActor::~MapActor()
{
}


void MapActor::updateMap(MapHandle handle, ColorMap & objectColors, bool
heightColor)
{
    updateTimer.start();

    mapHandle = handle;

    // Create points
    if (!points)
    {
        cout << "creating points" << endl;
        points = vtkSmartPointer<vtkPoints>::New();
        points->SetNumberOfPoints(mapHandle->size()*8);
    }

    if (!normals)
    {
        normals = vtkSmartPointer<vtkFloatArray>::New();
        normals->SetNumberOfComponents(3);
        normals->SetName("normals");
        normals->SetNumberOfTuples(mapHandle->size());
    }

    //    if (!celldata)
    {
        celldata = vtkSmartPointer<vtkCellArray>::New(); // we want to
create a new cell data every time, for garbage collection
        // the docs say there is now way to pre-allocate celldata storage...
    }

    // add points for elevation cells
    Point p;
    float resolution = mapHandle->resolution();

    VirtualMap::MapType::iterator it, endIt;
    int cellCount = 0;
    int pointCount = 0;
    vtkIdType indicies[14];

    it = mapHandle->begin();
    endIt = mapHandle->end();

    double minZ, maxZ;
    float normal[3];
    double dcolor[3];
    unsigned char color[3];

    minZ = 999999;
    maxZ = -999999;

    if (!colors)
    {
        colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
        colors->SetName("colors");
        colors->SetNumberOfComponents(3);
        colors->SetNumberOfTuples(mapHandle->size()*14);
    }

    while (it != endIt)
    {
        mapHandle->getPoint(p,it);

        float height = -1*it->height();
        if (height <= 0) height = 0.01;

        double z = -1*it->ground();

        if (heightColor == true)
        {
            // set color
            heightLut->GetColor(height,dcolor);
        }
        else
        {
            dcolor[0] = objectColors[it->classType()].red();
            dcolor[1] = objectColors[it->classType()].green();
            dcolor[2] = objectColors[it->classType()].blue();
        }

        color[0] = static_cast<unsigned char>(255.0 * dcolor[0]);
        color[1] = static_cast<unsigned char>(255.0 * dcolor[1]);
        color[2] = static_cast<unsigned char>(255.0 * dcolor[2]);

        // bottom front left
        indicies[0] = pointCount;
        points->SetPoint(pointCount,p.x(),-p.y(),z);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = -1;
        normal[1] = -1;
        normal[2] = -1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // top front left
        indicies[1] = pointCount;
        points->SetPoint(pointCount,p.x(),-p.y(),z+height);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = -1;
        normal[1] = -1;
        normal[2] = 1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // bottom front right
        indicies[2] = pointCount;
        points->SetPoint(pointCount,p.x()+resolution,-p.y(),z);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = 1;
        normal[1] = -1;
        normal[2] = -1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // top front right
        indicies[3] = pointCount;
        points->SetPoint(pointCount,p.x()+resolution,-p.y(),z+height);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = 1;
        normal[1] = -1;
        normal[2] = 1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // bootom back right
        indicies[4] = pointCount;
        points->SetPoint(pointCount,p.x()+resolution,-p.y()-resolution,z);
 // <- should this be -resolution?
        colors->InsertTupleValue(pointCount,color);
        normal[0] = 1;
        normal[1] = 1;
        normal[2] = -1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // top back right
        indicies[5] = pointCount;

points->SetPoint(pointCount,p.x()+resolution,-p.y()-resolution,z+height);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = 1;
        normal[1] = 1;
        normal[2] = 1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // bottom back left
        indicies[6] = pointCount;
        points->SetPoint(pointCount,p.x(),-p.y()-resolution,z);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = -1;
        normal[1] = 1;
        normal[2] = -1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;
        // top back left
        indicies[7] = pointCount;
        points->SetPoint(pointCount,p.x(),-p.y()-resolution,z+height);
        colors->InsertTupleValue(pointCount,color);
        normal[0] = -1;
        normal[1] = 1;
        normal[2] = 1;
        normals->InsertTupleValue(pointCount,normal);
        pointCount++;

        // close box
        indicies[8] = indicies[0];
        indicies[9] = indicies[1];
        // add top
        // degenerate triangle
        indicies[10] = indicies[1];
        indicies[11] = indicies[7];
        indicies[12] = indicies[3];
        indicies[13] = indicies[5];

        // indicies[12] = ;

        //       celldata->InsertNextCell(triangleStrip);
        celldata->InsertNextCell(14,indicies);

        if (height < minZ) minZ = height;
        if (height > maxZ) maxZ = height;

        ++it;
        ++cellCount;
    }

    polydata = vtkSmartPointer<vtkPolyData>::New();

    polydata->SetPoints(points);
    polydata->GetPointData()->SetNormals(normals);
    polydata->SetStrips(celldata);

    //  polydata->Update();
    // polydata->GetCellData()->SetScalars(colors);  well this doesn't work
right...
    polydata->GetPointData()->SetScalars(colors);
    polydata->Modified();

    // Create a mapper and actor
    //    if (!mapper)
    {
        mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    }

    //mapper->SetInputConnection(glyph3D->GetOutputPort());
    mapper->SetInput(polydata);

    actor->SetMapper(mapper);
    // actor->GetProperty()->BackfaceCullingOn();

    updateTimer.stop();

    cout << "map update took: " << updateTimer.elapsedDouble() << ", avg: "
<< updateTimer.averageElapsedDouble() << endl;
}
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20120902/0b0c036e/attachment.htm>


More information about the vtkusers mailing list