# Low FPS for transforming surfaces

**URL:** <https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571>\
**Category:** Development\
**Created:** [December 20, 2019, 12:52pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571 "2019-12-20T12:52:51Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [December 20, 2019, 12:52pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/1 "2019-12-20T12:52:51Z")

</div>

We want to transform 3D models in ‘real time’ in 3D Slicer with data coming from outside. The problem is, that the frame rate we currently reach is very low. Below is some demonstration code to show our approach:

hpp:

```auto
QTimer fpsTestUpdateTimer;
vtkSmartPointer<vtkTransform> fpsTestTransform;
vtkMRMLTransformNode* fpsTestTransformNode;

```

cpp:

```auto
{
    ...
    connect(&fpsTestUpdateTimer, &QTimer::timeout, this, &MovementDemo::fpsTestTimerCallback);
    ...
}

//----------------------------------------------------------------------------
void MovementDemo::startStopFpsTest(bool enable, int fps)
{
    if (!enable)
    {
        fpsTestUpdateTimer.stop();
    }
    else if(!trackingUpdateTimer.isActive())
    {
        qSlicerApplication* app = qSlicerApplication::application();
        fpsTestTransform = vtkSmartPointer<vtkTransform>::New();
        fpsTestTransform->RotateZ(1);
        fpsTestTransformNode = vtkMRMLTransformNode::SafeDownCast(app->mrmlScene()->GetFirstNodeByName("FpsTestTransform"));
        fpsTestUpdateTimer.start(1000 / fps);
    }
}

//----------------------------------------------------------------------------
void MovementDemo::fpsTestTimerCallback()
{
    fpsTestTransformNode->ApplyTransform(fpsTestTransform);
}

```

The transform is applied to a model with about 1600 vertices.  
On a screen with a resolution of 1920x1080, where the 3D view occupies about half of the screen space, we get about 10-20 fps (according to the fps display of the 3D viewer).  
When I activate the ‘3D view rock’ ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/8/78114c9d4f9a4d77516a8b8b65e415c769d0266c.png).

Here are two videos for illustration (and because of the season):  
Change transform:  
 ![v15](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/d/0/d083a4d1997bcf7d081677756c946d8cd55ebf53.gif)

Rock animation:  
 ![v60](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/5/f/5fe527adc2f2a02987c6be52a353e1afebfcad2c.gif)

Any help regarding optimization possibilities is greatly appreciated.  
Happy holidays!

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [December 20, 2019, 1:51pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/2 "2019-12-20T13:51:12Z")

</div>

`ApplyTransform` modifies the polydata in each iteration, which is time-consuming and in the long term even some error in the point coordinates may accumulate.

If you want to rotate the viewpoint then modify the camera position (this is done when you activate 3D view rock feature). If you want to modify an object pose then set its parent transform once, then modify the matrix in the transform node at each iteration.

---

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [December 20, 2019, 2:47pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/3 "2019-12-20T14:47:48Z")

</div>

Thank you Andras, I adapted my code to the following:

```auto
//----------------------------------------------------------------------------
void MovementDemo::fpsTest(bool enable, int fps)
{
    if (!enable)
    {
        fpsTestUpdateTimer.stop();
    }
    else if(!trackingUpdateTimer.isActive())
    {
        qSlicerApplication* app = qSlicerApplication::application();

        fpsTestUpdateTimer.start(1000 / fps);
        fpsTestTransformNode = vtkMRMLLinearTransformNode::SafeDownCast(app->mrmlScene()->GetFirstNodeByName("FpsTestTransform"));
        fpsTestTransform = vtkTransform::SafeDownCast(fpsTestTransformNode->GetTransformToParent());
    }
}

//----------------------------------------------------------------------------
void MovementDemo::fpsTestTimerCallback()
{
    fpsTestTransform->RotateZ(1);
    fpsTestTransformNode->Modified();
}

```

The results are better - some data:

fps setting (= 1000 / timer callback rate) --\> displayed fps  
30 --\> 20  
40 --\> 30  
50 --\> 30  
60 --\> 30  
80 --\> 33  
100 --\> 35  
120 --\> 33  
200 --\> 40  
300 --\> 40  
500 --\> 40

I don’t quite understand the connection between my timer repetition rate and the resulting frame rate. Can it be connected with vsync? Just for information: the CPU load during the test (fps setting 120) is around 5%, the GPU load at around 10%.

I really would like to reach a refresh rate of 60Hz for this simple example. Are there any more suggestions for what I could try to do? Would it help to call ‘forceRender’ like it is done in the rock animation? [https://github.com/commontk/CTK/blob/78341abaf1c56bbdcc70372ffefed91e2a940d32/Libs/Visualization/VTK/Widgets/ctkVTKRenderView.cpp#L190](https://github.com/commontk/CTK/blob/78341abaf1c56bbdcc70372ffefed91e2a940d32/Libs/Visualization/VTK/Widgets/ctkVTKRenderView.cpp#L190)

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [December 20, 2019, 3:25pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/4 "2019-12-20T15:25:12Z")

</div>

vsync caps the refresh rate at 60Hz (probably on a simple rendering you could do hundreds of fps).

`scheduleRender` mechanism in [ctkVTKAbstractView](https://github.com/commontk/CTK/blob/master/Libs/Visualization/VTK/Widgets/ctkVTKAbstractView.h#L110-L131) optimizes number of actual renderings in response to `scheduleRender` requests. By default refresh rate is capped at 60Hz and up to 1 frame latency is introduced, but it is a small price to pay considering that it eliminates unnecessary re-renderings.

For replaying animations at a fixed frame rate you may circumvent scheduleRender mechanism and issue forceRender calls at regular time intervals. This should not be a problem as long as there is only one component that does this (if you had multiple sources of forceRender then your application could slow down due to many unnecessary re-renderings).

---

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [January 8, 2020, 4:48pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/5 "2020-01-08T16:48:33Z")

</div>

just to share my experiences here:

`scheduleRender` clearly would be the desired solution, however, I never managed to reach a frame rate \> 40 (according to the fps display of the 3d view), when calling `scheduleRender` 80-500 times a second with an empty scene and with the window sized such that the 3d view has 300x400px. As said, the rock animation renders with 60 fps.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [January 8, 2020, 5:15pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/6 "2020-01-08T17:15:21Z")

</div>

One possible reason you do not reach the maximum target refresh rate (60fps by default) is that transforming a node is a costly operation (in contrast what “3D view rock” does - just rotating the camera). It may also trigger update of multiple views, which may further slow down the rendering. You can build in RelWithDebInfo and run the code with a profiler to get definitive answer.

---

<div class="post-metadata">

**Author:** ![rprueckl](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/rprueckl/32/4240_2.png) [@rprueckl](https://discourse.slicer.org/u/rprueckl)\
**Post date:** [January 8, 2020, 5:30pm UTC](https://discourse.slicer.org/t/low-fps-for-transforming-surfaces/9571/7 "2020-01-08T17:30:39Z")

</div>

Oh, I forgot to mention, I commented out any transform manipulation in my last test - so only the following code reaches a maximum of 40 fps:

```auto
void MovementDemo::fpsTestTimerCallback()
{
    if (!animationIntervalMs)
    {
        return;
    }

    threeDView->scheduleRender();

    QTimer::singleShot(animationIntervalMs, this, SLOT(fpsTestTimerCallback()));
}

```

When I use `forceRender`, the 60 fps can be reached.  
I am currently thinking about updating the view constantly with 60 Hz using `forceRender` and performing the updates of the transforms with another timer.
