0

I am trying to implement (fairly) simple scene where I have ~50 cubes which are moving in certain directions. The position of the cubes changes 20 times per second.

My first shoot was adding and removing actors from the scene. This approach just doesn't scale. Whole scene lags and user is unable to move the camera.

void draw(vtkRenderer *renderer)
{    
    renderer->RemoveAllViewProps(); 
    for(const Cube& cube : cubes_)
    {
        vtkSmartPointer<vtkCubeSource> cube_source = vtkSmartPointer<vtkCubeSource>::New();  
        cube_source->Update();
        cube_source->SetXLength(cube.lengt());
        cube_source->SetYLength(cube.width());
        cube_source->SetZLength(cube.height());

        vtkSmartPointer<vtkPolyDataMapper> poly_mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
        poly_mapper->SetInputConnection(cube_source->GetOutputPort());

        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(poly_mapper);
        actor->SetPosition(cube.x(), cube.y(), cube.z());

        renderer->AddActor(actor);
    }
}

Second shot is a bit better. I have created "actor pool" where I reuse the actors and hide the ones which are not needed. Still, moving camera is laggy and the rest of my UI (I have some additional widgets inside Vtk widget) seems to be laggy.

I couldn't find any relevant source for Vtk where scene is "dynamic". All examples preload all scene elements and further work with them. Can anyone tell me what am I doing wrong here?

carobnodrvo
  • 1,021
  • 1
  • 9
  • 32
  • I can show my example! – Vahagn Avagyan Jul 25 '17 at 15:42
  • 1
    Hi, your second approach sounds like it should work, I just tried on of my codes to simply set the position of the actor through actor->SetPosition before each render (without re-setting the actors, just setting the position) and didn't see any lag (also ~50 actors). If you post your second-approach code, maybe we can find what is wrong (I don't know about any tutorial about this to point you to, sorry). Also, is the 20fps rendering loop running smoothly if you don't do the position changes? So that we can rule out that the problem is in fact in your animation loop code... – tomj Jul 26 '17 at 08:16
  • Hey, I actually found out why is it happening. On my laptop, camera transition starts to lag if I add more then 70 actors to the scene! So, I assume that there shouldn't be a loot of actors in the scene. Futher, my approach is now to use `vtkGlyph3D`, where instead of 50 actors I have only one and I am not deleting this actor, instead only changing the points. This seems to be perfect solution since movement of my camera is smooth now. I could put up the code if someone needs it. – carobnodrvo Jul 27 '17 at 07:07
  • That is quite a common problem and yes, vtkGlyph3D is a good solution. It's just a bit strange that it happens for you for such a relatively low amount of actors, most people run into such problems when the actor count reaches the order of hundreds. Well, anyway, If I may, I would suggest you to make an answer yourself (perhaps with the code snippet showing how you use the vtkGlyph3D) and mark it as accepted so that the question is resolved. – tomj Jul 27 '17 at 08:13
  • I will, as soon as I resolve final issue. It is irrelevant for the question above, but do you maybe know how to set size of a cube in `vtkGlyph3D`? (I do not want scale but given size set it to exect same size...) – carobnodrvo Jul 27 '17 at 08:28
  • `SetScaleModeToScaleByVectorComponents()` was the function I was looking for :) – carobnodrvo Jul 27 '17 at 08:46

2 Answers2

2

So afther some days of reaserch I managed to hack working solution:

vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
// as many points as you like
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);


vtkSmartPointer<vtkFloatArray> scales = vtkSmartPointer<vtkFloatArray>::New();
scales->SetNumberOfComponents(3);
// same as number of points
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);


vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
polydata->GetPointData()->SetVectors(scales);

vtkSmartPointer<vtkCubeSource> cubeSource = vtkSmartPointer<vtkCubeSource>::New();

vtkSmartPointer<vtkGlyph3D> glyph3D = vtkSmartPointer<vtkGlyph3D>::New();
glyph3D->OrientOff(); // disable orientation
glyph3D->SetScaleModeToScaleByVectorComponents(); // sacle along each axis
glyph3D->SetSourceConnection(cubeSource->GetOutputPort());
glyph3D->SetInputData(polydata);
glyph3D->Update();

vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(glyph3D->GetOutputPort());
mapper->ScalarVisibilityOff(); // use color from actor

vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->GetProperty()->SetColor(0, 1, 0); // this will change color for whole glyph
actor->SetMapper(mapper);

mapper->Update();

vtk_renderer->AddActor(actor);

Code from above will add as many cubes and you want using a single actor! (which was amazing performance boost in my case)

Further, if you want to update positions of the cubes, you just need to do following:

points->Reset();
points->InsertNextPoint(-25, 0, 0);
points->InsertNextPoint(-35, 0, 0);

scales->Reset();
scales->InsertNextTuple3(1, 1., 8.);
scales->InsertNextTuple3(1., 1., 10.);

polydata_->Modified();
// call render

(notice that I am not removing/adding actors to the scene which is another boost)

carobnodrvo
  • 1,021
  • 1
  • 9
  • 32
1

this my visualization VTK example

.....
    vtkSmartPointer<vtkRenderer> m_vtkRenderer;
    vtkSmartPointer<MouseInteractor> m_mouseInteractor;
    QVector<vtkActor* > m_parcellationActors;
    QVector<vtkActor* > m_electrodesActors;
    QVector<vtkFollower* > m_textActors;
    QVector<vtkActor*> m_vectorFieldsActors;
    QVector<vtkActor*> m_streamlinesActors;
......
  void VisualizationWidget::create3DViewArea()
    {

    m_3DViewArea = new QStackedWidget(this);
    m_vtkWidget = new QVTKWidget(m_3DViewArea);
    m_vtkRenderer = vtkSmartPointer<vtkRenderer>::New();
    m_vtkRenderer->SetBackground(0.4, 0.4, 0.4);
    this->m_vtkWidget->GetRenderWindow()->AddRenderer(m_vtkRenderer);
    m_mouseInteractor = vtkSmartPointer<MouseInteractor>::New();
    m_mouseInteractor ->SetDefaultRenderer(m_vtkRenderer);
    this->m_vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle( m_mouseInteractor);
    connect(m_mouseInteractor, &MouseInteractor::onActorSelected, this, &VisualizationWidget::onActorSelectedSlot);
    m_vtkLoadingWidget = new LoadingWidget(m_3DViewArea);
    m_vtkLoadingWidget->setIconPath(Icon::s_getTDCSLoadingGif);
    m_3DViewArea->addWidget(m_vtkLoadingWidget);
    m_3DViewArea->addWidget(m_vtkWidget);
}


void VisualizationWidget::setParcellationActors(QVector<vtkActor*> actors)
{
    m_parcellationActors = actors;
    for (int i = 0; i < m_parcellationActors.size(); ++i) {
        m_vtkRenderer->AddActor(m_parcellationActors.at(i));
    }

    m_vtkWidget->update();
}
void VisualizationWidget::setElectrodesActors(QVector<vtkActor*> actors)
{
    m_electrodesActors = actors;

    for (int i = 0; i < m_electrodesActors.size(); ++i) {
        m_vtkRenderer->AddActor(m_electrodesActors.at(i));
    }
    m_vtkWidget->update();
}

void VisualizationWidget::setElectrodesLabelsActors(QVector<vtkFollower*> actors)
{
    m_textActors = actors;

    for (int i = 0; i < m_textActors.size(); ++i) {
        m_textActors.at(i)->SetCamera(m_vtkRenderer->GetActiveCamera());
        m_vtkRenderer->AddActor(m_textActors.at(i));
    }
    m_vtkRenderer->ResetCamera();
    m_vtkWidget->update();
}

void VisualizationWidget::setVectorFieldsActors(QVector<vtkActor*> actors)
{
    for (int i = 0; i < m_vectorFieldsActors.size(); ++i) {
        m_vtkRenderer->RemoveActor(m_vectorFieldsActors.at(i));
    }
    m_vectorFieldsActors = actors;

    for (int i = 0; i <  m_vectorFieldsActors.size(); ++i) {
        changeActorOpacity(m_vectorFieldsActors[i], double(m_postProcResOpacSliders.at(i)->value()) / m_postProcResOpacSliders.at(i)->maximum());
        m_vtkRenderer->AddActor(m_vectorFieldsActors.at(i));
    }

    m_vtkRenderer->ResetCamera();
    m_vtkWidget->update();
}

void VisualizationWidget::setStreamlinesActors(QVector<vtkActor*> actors)
{
    for (int i = 0; i < m_streamlinesActors.size(); ++i) {
        m_vtkRenderer->RemoveActor(m_streamlinesActors.at(i));
    }
    m_streamlinesActors = actors;

    for (int i = 0; i < m_streamlinesActors.size(); ++i) {
        changeActorOpacity(m_streamlinesActors[i], double(m_streamLinesSlider->value()) / m_streamLinesSlider->maximum());
        m_vtkRenderer->AddActor(m_streamlinesActors.at(i));
    }

    m_vtkRenderer->ResetCamera();
    m_vtkWidget->update();
}

void VisualizationWidget::changeActorOpacity(vtkActor* actor, double opac)
{ 
    actor->SetVisibility(opac > 0.05);
    actor->GetMapper()->Modified();
    actor->GetProperty()->SetOpacity(opac);
}
Vahagn Avagyan
  • 750
  • 4
  • 16
  • Thanks for your snippet! This is similar to my second approach. If you want (need) to boost your performance even more check my comment above. Cheers! – carobnodrvo Jul 27 '17 at 07:08