New version of Ab3d.PowerToys and Ab3d.DXEngine with multi-threaded rendering

by abenedik 20. February 2019 16:10

I am very happy to inform you that new versions of our 3D libraries have been published.

The greatest new feature of this release is that the Ab3d.DXEngine now supports multi-threaded rendering. This can provide an amazing performance boost - in some cases, the time required to render one frame has been reduced by more than 4 times = 400% improvement.

This version also adds support for showing object outlines and provides a few improvements and additional options for rendering instanced objects. It also fixes a few bugs, especially with some hit testing use cases.

The main focus of the new Ab3d.PowerToys library version is on improved camera controller. This should prevent problems with mouse rotation and movement when using custom rotation or zoom position. There is also a new QuickZoom zooming mode that provides a very fast and precise zooming option for the user.

Let me first provide some additional details about the new multi-threading capabilities. The following graph shows the total time that is needed to render one frame where the number of used background threads is shown on the x axis:

Ab3d.DXEngine multi-threading performance improvements graph

The data was created by the new benchmark test that is now part of the Ab3d.DXEngine samples. It shows the rendering 160.000 (!!!) boxes without using instancing (each is defined by its own SceneNode object). The test was executed on Intel i7 6700K CPU (4 cores with hyperthreading) and NVIDIA 1080 GTX graphics card. As you can see the new multi-threading capabilities can provide 4 times the performance of a single threaded rendering. It is also incredible that now it is possible to render so many individual objects with almost 60 FPS (55 FPS in this test).

When describing the results I need to tell that those results were achieved with using DirectXOverlay PresentationType. This means that the 3D scene is rendered on top of the WPF content - in this case the graphics card can render the scene in the background and when the rendering is completed it can show the rendered image. This means that the Ab3d.DXEngine does not need to wait for the graphics card to finish rendering. On the other hand, when DirectXImage is used as a PresentationType, the 3D scene is composed with other WPF objects (other WPF objects can be seen through the scene and other WPF objects can be shown on top of the 3D scene). But for this to work, the Ab3d.DXEngine needs to wait until the graphics card finishes rendering the scene and this significantly increases the total rendering time. In case of using multi-threading this means that Ab3d.DXEngine can issue all the DirectX state changes and draw calls much faster compared to a single threaded rendering. But this also means that the time to wait for the graphics card to finish rendering increases significantly. Therefore the performance improvements are not as great as with DirectXOverlay, but still, the scene with 160.000 boxes can be rendered almost 3 times faster - see graph:

Ab3d.DXEngine multi-threading performance improvements graph

So, if you are rendering complex 3D scenes with many objects, you can expect great performance gains just with upgrading to a new Ab3d.DXEngine version. What is more, when rendering many 3D objects the CPU is usually the bottleneck of the whole process. But with greatly increasing throughput of the CPU, the graphics card can become the bottleneck. And because the performance of the graphics cards increases significantly with each new graphics card version, it is possible to further improve the performance with upgrading the graphics card (upgrading CPU to a new version usually do not provide such benefits).

Note that multi-threading only helps when the scene contains many 3D objects - in this case many DirectX commands needs to be executed. When you are rendering only a smaller number of objects but that objects are very complex with a lot of triangles or when you are using object instancing to render many 3D objects, then the new multi-threading will not have any significant effect.

It is also worth mentioning that increasing the number of used CPU cores does not improve performance indefinitely. The tests have shown that for most use cases it is not worth using more the 8 cores. Therefore the Ab3d.DXEngine initially uses all the cores but not more than 8. This value is defined by DXScene.MaxBackgroundThreadsCount property (note that it counts only the background threads so value 7 means that 8 cores will be used: 1 main thread + 7 background threads).

To get more information about multi-threading in Ab3D.DXEngine you can read the online help for MaxBackgroundThreadsCount.

 

This new version also provides some improvements and additional options for rendering instanced objects. The most useful new option is to render the same instance data (same DirectX instance buffer) with using different InstancedMeshGeometry3DNode objects and providing different StartInstanceIndex and InstancesCount values for each InstancedMeshGeometry3DNode object. This way it is possible to hide multiple parts of the instanced objects without changing the instance buffer (which is a costly operation). A new sample that demonstrates that also shows how to override the color of the shown instances - this can be useful for showing selected objects with different color again without changing the instances data.

Let me also provide a few additional details about the new possibility to show object outlines. The following screenshot will illustrate what this means:

Ab3d.DXEngine with object oulines

As you see the new outlines can be used to provide great visual feedback to the user about the selected objects. The trick is that the outlines are visible through other 3D objects. To provide support for that, the Ab3d.DXEngine comes with a new ExpandPostProcess and a new sample that demonstrates how to alter the rendering process to render the object outlines.

The new version of Ab3d.DXEngine also adds support for showing object edges with using a sobel algorithm (https://en.wikipedia.org/wiki/Sobel_operator). The following screenshot shows an example of that:

Ab3d.DXEngine with sobel edge detection post process

 

There are also some other very important improvements and fixes. For a full list of changes see the history web page:

Ab3d.DXEngine versions history

Ab3d.PowerToys versions history

 

In this version of Ab3d.PowerToys I also wanted to update the version of the third-party Assimp importer (imports 3D objects from many file formats). Because the official release is from December 2017 I went to GitHub and get the latest source. I compiled the source into native libraries. But after doing some tests I have found out that some of the 3D files were not imported correctly. Therefore I did not publish the new version. So this release comes with the official version (from December 2017) and also with a newer version that was published with the previous version with Ab3d.PowerToys (from May 2018).

Finally, I would like to say that I am following the .Net framework development news with great interest. Especially the part that with .Net Core 3 it will be possible to build WPF and WinForms apps. I have already tried to compile the Ab3d.PowerToys and Ab3d.DXEngine libraries with the preview version of the .Net Core 3 and they have both compiled fine and also run very well. This means that when an official version of .Net Core 3 will be released it will be also possible to get both Ab3d.PowerToys and Ab3d.DXEngine libraries compiled for that framework.

Tags: , , , ,

Ab3d.PowerToys | DXEngine