Major new version of Ab3d.PowerToys and Ab3d.DXEngine published

by abenedik 19. December 2025 16:36

I would like to inform you that I have just published a major new version of Ab3d.PowerToys and TWO new versions of Ab3d.DXEngine. One new Ab3d.DXEngine has version 7.2, and the other has version 8.0.

Both v7.2 and v8.0 of Ab3d.DXEngine versions have the same features, but version 8.0 introduces breaking changes because it no longer requires the SharpDX library. Instead, it defines all the required DirectX 11 interop inside the library. Because the new interop structs and classes have new namespaces, this requires some changes in the code that uses the library. But if you just want to use the new features without changing your code, you can upgrade to version 7.2.

But before I describe the differences between those two versions in more detail, let me quickly mention some other major new features. This time, the Ab3d.PowerToys got more major new features. Here is a quick list:

  • Added camera rotation, movement and zoom smoothing to MouseCameraController.
  • Improved model slicing by adding support to close the sliced models.
  • Improved BezierCurve and BSpline classes by adding methods that use an adaptive algorithm that generates the curve position based on angle change.

The following are two additional major improvements for the new Ab3d.DXEngine library:

  • Improved ID bitmap performance by reading only part of the rendered ID bitmap from the GPU memory.
  • Added Points3DTo2D methods to DXScene that can calculate 2D screen positions much faster than the same method from Ab3d.PowerToys library.

 

After the overview, let me now continue with the details about the DXEngine without the SharpDX library.

First, let me explain why I'm providing a special version without the SharpDX library.

Because the SharpDX project has not been actively developed for quite some time (the last NuGet package was published in 2018), some of my customers have expressed concern about the library.

In my opinion, the SharpDX code is one of the best-written .NET libraries. Also, the DirectX 11 API is no longer changing, so the existing code does not require any additional changes. What is more, because SharpDX used clever IL rewrites, the DirectX interop calls are as fast as if newer unmanaged function pointers were used.

On the other hand, some of the structs that are defined in the SharpDX library, like Vector3 and Matrix, now have similar structs in System.Numerics namespace that is part of the .Net. Because the new structs are highly optimized to use new SIMD and vector instructions, they can be significantly faster than using the structs from SharpDX. For example, my benchmarks (using BenchmarkDotNet) show that the matrix multiplication is around 4 times faster when using Matrix4x4 from System.Numerics instead of Matrix from SharpDX. Also, the Points3DTo2D method that calculates 2D screen positions from an array of 3D positions is almost twice as fast when using System.Numerics. But on the other hand, most other methods and all DirectX 11 API calls are not significantly faster. Therefore, if you are not doing a lot of Vector3 and Matrix calculations, you should not expect bigger performance improvements. Anyway, if you decide to use the new version 8.0, then please use the Guide to upgrade to v8.0.

Also note that Ab3d.DXEngine does not define all the DirectX 11, Direct3D, and DXGI classes and functions (only the functions actually used by Ab3d.DXEngine are defined). If you use your own low-level code that communicates with DirectX 11, and you require some functions that are not defined in the new Ab3d.DXEngine, then you may still need to use SharpDX or some other library (like Vortice.Direct3D11). However, if you are missing just one or a few functions, please send me an email with the list of missing interop functions, and I may add them to Ab3d.DXEngine.

Another important note about version 8.0 is that it requires .Net 10. This is needed to define instance extension methods so that even though the structs from the System.Numerics namespace do not define the same methods as structs from SharpDX, the new extensions allow defining all the required methods from SharpDX. For example, SharpDX.Matrix defines the Transpose method that does not exist in the System.Numerics.Matrix4x4. The new extensions support in C# 14 allows us to define the missing instance Transpose method in the Matrix4x4 struct. Without that, we would need to use many #if and #endif statements with different code paths.

If you can use .Net 10 and you are willing to make some changes to your code, then it is recommended to switch to v8.0 instead of v7.2. This will also make your app start a little bit faster because it will not need to read 4 SharpDX assemblies.

But you can still stay on v7.2. In the future, the new versions will maintain this duality (by releasing v7.3 and 8.1, etc.).

 

And now to other new features. I am very happy that I was able to provide the three mentioned features to the Ab3d.PowerToys library. They have been on my todo list for quite a while and were also requested by some of the customers.

I always say that intuitive and efficient camera controls are the heart of every 3D application. They are the main interface between the 3D scene and the user. In this regard, I am very happy to inform you that a new version provides support for smooth camera rotation, movement, and zooming. Before, when the user rotated the camera with the mouse, it rotated immediately. But in nature, things rarely move that rapidly and usually have an inertia that smooths their movement. Also, before, when the user zoomed the camera by using the mouse wheel, the camera’s distance was changed immediately - it looked like the camera jumped from one position to another. Now, rotation, movement and zooming can be animated nicely. To preserve backward compatibility, the smoothing is disabled by default. But it can be very easily enabled by setting the CameraSmoothing property on MouseCameraController to Slow, Normal or Fast (it is also possible to fine-tune the settings).

The following screenshot shows the new sample that demonstrates the camera smoothing (see the darker green line that smooths the Heading changes - represented by light green color).

Camera smoothing in Ab3d.PowerToys

For a more detailed demonstration, see the Camera smoothing video.

I would encourage you to try the new smoothing for a few days. After using that for a few days, I must say I now find the old “immediate camera mode” very unnatural. Therefore, I am sure that by adding only a single line of code to enable camera smoothing, you will give your users a subtle but substantially better user experience.

 

Another interesting feature that has been a part of Ab3d.PowerToys for a very long time is slicing 3D meshes and models. This allows any 3D mesh or model to be sliced by a 3D plane. But after slicing, you could always see inside the sliced models. But with the new version, you can now close the sliced models. You can also create a single 3D mesh that represents the slice (a planar mesh that represents the 3D plane inside the mesh).

What is more, the slice code has been moved from the Plane struct to the new Slicer class. This cleans the Plane structs by removing the temporary collection from the struct, leaving Plane with only the data required to define the 3D plane. 

See the screenshot from the new Slicer sample:

New mesh slicing sample in Ab3d.PowerToys

Closing sliced mesh

And as before, here is a short video from the slicer sample.

 

The last interesting new feature from the Ab3d.PowerToys is improved support for generating Bezier and BSpline curves. Before, you specified a fixed number of positions per segment that always generated the same number of positions between two curve segments. This is very fast to compute, but can generate too many points along nearly straight sections and too few where the curve bends sharply.

With the new version, the curve positions can also be generated by using an adaptive algorithm. It adds more points where the curvature is higher. This takes longer to compute, but generates smoother curves with fewer positions.

The following screenshot shows the new angle-based adaptive algorithm in action:

Bezier curves with angle based positions generation

You can compare that with the fixed points-per-segment method (this generates 91 positions but has worse accuracy than 56 positions of the angle-based method):

Bezier curves with fixed position generation

 

The Ab3d.DXEngine got two new features that can significantly improve performance in some of the use cases.

The first is great when using the ID bitmap for hit testing. Standard hit testing is done by creating a 3D ray and checking whether it intersects any triangles in the mesh (before checking all triangles, the mesh's bounding box is checked for ray intersection). When there are a lot of objects in the 3D scene or when the meshes have a lot of triangles, the hit testing code may need to execute millions of ray-to-triangle intersection tests. For large meshes, the DXEngine can also use OctTrees, which can significantly reduce the number of tests, but this can still be an expensive CPU operation.

An alternative to the standard hit testing is to render the 3D scene to a bitmap, but instead of using the usual materials, the objects are rendered with colors that are generated from their IDs. This way, it is possible to get the object ID from the color on the rendered bitmap. In some cases, this can work much faster.

But when the application’s window is large (for example, 4k), it takes a significant amount of time to copy the rendered bitmap from GPU memory to CPU memory. The new version can solve that problem by preserving the rendered bitmap in GPU memory and copying only a small portion of it to CPU memory. This can be much faster.

See the updated VertexIdBitmapHitTesting and InstancedIdBitmapHitTesting samples on how to use this new feature.

 

Another performance improvement in DXEngine is a new way to calculate 2D screen positions from a list of 3D positions. To achieve that, you can use the Points3DTo2D method on the Ab3d.PowerToys’s camera object. The method takes an array of Point3D items and fills another array of Point items with 2D screen coordinates. As with most of the operations in WPF, those calculations are done by using double precision (using Point3D and Matrix3D). But with DXEngine, you can also use optimized Vector3 to represent a 3D position. This uses float values and can be further optimized by using SMID and vector operations.

So, if you need to calculate 2D screen positions, the new version of Ab3d.DXEngine provides a new Points3DTo2D method on the DXScene object. This method takes an array of Vector3 items instead of an array of Point3D items. Because the new method uses float values, the code in v7.2 is 10 times faster than the same method from Ab3d.PowerToys library (and 20 times faster when using v8.0 without SharpDX). For example, calculating 10,000 screen positions takes around 0.34 ms when using the camera’s Points3DTo2D method. When using this method on the DXScene withAb3d.DXEngine v7.2 that operation takes 0.035 ms and when using v8.0 it takes 0.0173 ms. Note that if you need to convert only a few positions, then you can use either method (depending on whether you use Point3D or Vector3).

As always, there are also many other smaller improvements and fixes. See the Ab3d.PowerToys change log and Ab3d.DXEngine change log.

 

Until now the Ab3d.PowerToys and Ab3d.DXEngine libraries have been distributed by using NuGet packages and also by using the commercial version installer (msi file downloaded from the User Account web page). Because this requires maintaining two different versions of the library and two different sample projects, and because I am not going to renew the recently expired Microsoft code signing certificate that was used to sign the msi installer, I have decided that this version is the last version that is distributed by both methods. This means that future versions will be distributed only by NuGet packages. Therefore, if you are still using the commercial installer, I would encourage you to migrate to the NuGet package distribution.

 

In this version, I also wanted to publish a new Assimp importer. The native Assimp library has been updated to version 6.0.2, but this introduces some breaking changes when reading animation data. Therefore, the newly released version still uses Assimp v5.4.2. Anway, if you are using Assimp importer and do not require animation data, then you can still get the native binaries from the Assimp releases. After extracting the zip with binaries, rename the native dlls into Assimp64.dll or Assimp32.dll and copy the new version of those two files over the previous version. I will try to update the AssimpNet project to support new animation data structures in the following days. Then I will update the samples. So if you are interested in getting a new Assimp version with animation support, check the samples in the coming days.

 

This year, I also planned to release the first official version of the Ab4d.SharpEngine for the browser. But this has to be moved to January.

Also, the development version for the desktop and mobile Ab4d.SharpEngine library already has a ton of new features, including support for Physically Based Rendering (PBR) materials. I am planning to release this version in February.

 

And now, the only thing that is left for me is to wish you happy and peaceful holidays and all the best in the new year.

Tags: , , ,

Ab3d.PowerToys | DXEngine

New Ab3d.PowerToys and Ab3d.DXEngine published

by abenedik 5. December 2024 20:07

As usual, shortly after a new .Net release, I am releasing new versions of Ab3d.PowerToys and Ab3d.DXEngine.

This is another bigger release with great new features and some important fixes. But before revealing what is new for Ab3d.PowerToys and Ab3d.DXEngine, I would like to present a brand new product.

As long as I am providing 3D graphics libraries, there has been a single most requested feature: provide support for importing .step and .iges files

Finally, I would like to announce that this is now possible with the new Ab4d.OpenCascade library. See the screenshots from the new CadImporter sample application:

CAD Importer with import settings
CAD Importer with assembly hierarchy

So far it was possible to use ReaderObj, glTFImporter or Assimp importer to import 3D models from many file formats. But all those file formats store their models as triangles or simple meshes that were defined by simple polygons. So after importing the meshes, it was relatively easy to show them using a rendering engine. But CAD applications like SolidWorks, CATIA, Autodesk Fusion 360, Autodesk Inventor, Pro/Engineer, Siemens NX, and others define their 3D models by using mathematically defined surfaces. All of those applications can store the models to .step or .igen files. Importing 3D models from those files first requires understanding all surface types and then triangulating them into meshes with triangles. Only after that can they be sent to the graphics card to render them.

The new Ab4d.OpenCascade library uses a third-party native OpenCascade library to read .step and .iges files and triangulate their models. This way the CadImporter class from the Ab4d.OpenCascade library can get 3D meshes that can be used by Ab3d.DXEngine (or Ab4d.SharpEngine) to render the 3D objects. The importer also preserves the names and hierarchical structure of the CAD parts (Compound or Solid). The faces and edges that define the parts can be also retrieved. For each edge, it is possible to get the original curve with its parameters. For example, you can get a location and a radius for a Circle (as seen in the image above); for BSpline curve you can get control points (Poles), weights and knots. What is more, it is possible to get the exact part volume and surface area (not from triangulated mesh but from actual mathematically defined objects).

The third-party OpenCascade library has its own license that allows free commercial use. The Ab4d.OpenCascade library can be used freely when the library is used with Ab3d.DXEngine or Ab4d.SharpEngine. The library provides the imported data in standard .Net types (int, float, double, simple arrays and structs) so it can be used by any other .Net code without Ab3d.DXEngine or Ab4d.SharpEngine. But in this case the source code for the Ab4d.OpenCascade library needs to be purchased (contact support for more info).

This is the first version of the importer, so your feedback is much appreciated. If you want some additional data from the .step or .iges files or would like to use some additional functionality from the OpenCascade library, please let me know.

The sample CadImporter application can be downloaded from CadImporter GitHub page.

 

And now to the new Ab3d.DXEngine. My favorite new feature is the new DynamicPlanarShadowRenderingProvider. It can render soft planar shadows with shadow darkness based on the objects' distance from the shadow plane. A screenshot best describes this:

soft and dynamic planar shadows

This looks even better when seen live in the sample because the objects are animated, and this updates the shadow dynamically.

The DynamicPlanarShadowRenderingProvider renders a shadow to a texture that can be set to a material that is shown by a 3D plane. When using static 3D objects (for example in ModelViewer sample in Ab3D.DXEngine samples), the shadow can be rendered only once and then the same texture can be shown as long as the 3D scene does not change. In an animated scene, the shadow can be updated on each frame.

This puts the DynamicPlanarShadowRenderingProvider somewhere between the already existing shadow providers: PlanarShadowRenderingProvider and VarianceShadowRenderingProvider. The PlanarShadowRenderingProvider is the simplest option for rendering shadows. It transforms all 3D objects into flat 3D models (using a shadow matrix). This creates a sharp shadow that is easy to render. The VarianceShadowRenderingProvider is a more standard shadow provider - it renders the objects from the light's position to a so-called shadow map that stores the distances from the 3D objects to the light. Those distances are then used when rendering 3D objects to determine whether the rendered pixel is in shadow or not. This can render shadow on any object (not only to a flat plane). The Variance term in the name means that a special technique that provides softer shadows is used. The shadow is always the same color, regardless of the object's distance. This is accurate for light that comes from a single source. But in reality, most of the light comes from ambient light that bounces around the walls and other objects.

In this case, the shadow is dark only when close to the object, but when the object is farther away, the shadow is not that strong anymore. This is what the new DynamicPlanarShadowRenderingProvider tries to achieve. 

The DynamicPlanarShadowRenderingProvider renders the shadow to a texture that can be shown on a 3D plane. The shadow can also be rendered to a transparent texture. This is also seen in the screenshot above. 

However, when using VarianceShadowRenderingProvider, it was not possible to render the shadow to a transparent 3D plane. You always needed to have an opaque object to see the shadow. But with the new version, there is a new VarianceShadowMaterial that can be used to render the shadow to a transparent texture (areas that are not in shadow are transparent).

 

The new shadow provider can improve the visual quality of the rendered scene. But when using 3D lines, the feature that provides the most significant improvement in the visual quality is super-sampling (SSAA). Graphics cards provide hardware support for multi-sampled anti-aliasing (MSAA), which significantly improves rendering quality. But super-sampling takes that to another level and can produce super smooth 3D lines. When SSAA is used, the 3D scene is rendered to a bigger texture that is then down-sampled to the final size.

But the cost of rendering a bigger texture can be quite significant. By default, Ab3d.DXEngine does not use SSAA (NormalQualityHardwareRendering GraphicsProfile is used). But many users changed that to HighQualityHardwareRendering and that uses 4xSSAA. This renders the 3D scene to a texture with 4 times as many pixels (width and height are multiplied by 2). Because in Ab3d.DXEngine the lighting calculations are done in a pixel shader, this means that 4xSSAA requires 4 times more pixel shader executions compared to rendering a scene without SSAA (and there is also an additional cost of down-sampling). Luckily, the graphics cards are incredibly fast and this is usually not a problem.

But what if I tell you that the new version can achieve almost the same visual quality as the previous version but at half the cost? The previous version supported only the following values for super-sampling count: 1 (disabled), 4, 16 and 64. Those values increased the width and height by a factor of 2, 4, or 8. However, after some research, I found out that almost the same visual quality can be achieved by using 2xSSAA - increasing the number of pixels by 2. In this case, the width and height of the texture are increased by a factor of 1.41 (a square root of 2). Rendering a scene with 2xSSAA can be done twice as fast as 4xSSAA because it requires only half of the pixel shader invocations.

So, the new version of Ab3d.DXEngine supports all values from 1 to 64 for super-sampling count, including 2, 3, and others. There is also a new OptimizedHighQualityHardwareRendering GraphicsProfile that supports 2xSSAA.

See the following screenshot for comparison:

super smooth lines sample

The top left part shows rendering without any anti-aliasing. The top right shows the improvement when using 4xMSAA (multi-sample anti-aliasing). The bottom left uses the new 2xSSAA (super-sampling anti-aliasing) + 4xMSAA. The bottom right uses 4xSSAA + 4xMSAA. The visual quality between the bottom two renderings is almost the same, but the left version is twice faster to render.

The following code enables the new OptimizedHighQualityHardwareRendering:

MainDXViewportView.GraphicsProfiles = new GraphicsProfile[]
{
    GraphicsProfile.OptimizedHighQualityHardwareRendering, // 2xSSAA + 4xMSAA
    GraphicsProfile.NormalQualitySoftwareRendering, // 4xMSAA
    GraphicsProfile.Wpf3D
};

 

The last new feature that I would like to describe in more detail is support for pixel hit-testing and point-cloud hit-testing.

From the first version on the Ab3d.DXEngine supports the standard hit-testing that generates a ray from a camera and mouse coordinates and then checks which triangles are intersected by the ray. Later a special hit testing that use ID bitmap was introduced. In this case, the whole scene is rendered in such a way that each 3D object gets a color that is calculated from the object's ID. This way, it is possible to check what color is under the mouse and from the color get the ID of the object. This is also very useful for mesh instancing where a huge number of meshes are rendered. In this case, it would take very long to check each mesh for ray intersections.

With the new version, it is also possible to render ID bitmap from pixels. To support that, set the new UseVertexIdColor property on the PixelEffect to true. This will render each pixel by a color that is defined from the index of the pixel.

To see that in action, check the new "Ab3d.DXEngine hit testing / Using Vertex ID Bitmap" sample. The sample also provides support for measuring distances on a point-cloud. See the screenshot:

point-cloud hit testing

The used ID bitmap can be seen in the bottom right corner.

 

There are also some other new features. And as always, this version also comes with some bug fixes. Let me mention just some of them:

  • fixed selecting lines with LineSelectorData when some lines are completely behind the camera,
  • fixed FitIntoView in some cases when parent ModelVisual3D objects have transformation applied,
  • improved edge line generation,
  • prevented showing render artifacts (may be shown as partially rendered image while camera is rotated rapidly),
  • prevented some exceptions like "childNode is already child of another SceneNode" and "StartBackgroundWaiting was called ..."

See the whole list of changes here and here.

To see the changes by yourself it is best to get the latest version of Ab3d.PowerToys samples and Ab3d.DXEngine samples. Check for NEW and UP icons (UP icons also provide a tooltip with additional information). If your updated subscription has already expired, you can still still get the new samples and start them. This will start a new trial version for the new version. If you have an expired subscription and have used the libraries for at least 2 years, contact me for a renewal discount (valid only in December).

 

Next week, I plan to release a new beta version of Ab4d.SharpEngine with many new features. Then until the end of February the new official version of Ab4d.SharpEngine will be released. If you want to purchase the Ab4d.SharpEngine, then now is the best time to do that because you can use a 30% discount in December.

And because we are already in December, I would like to wish you happy and peaceful holidays and all the best in the new year.

Tags: , , ,

Ab3d.PowerToys | DXEngine

New bug fix Ab3d.DXEngine published

by abenedik 12. July 2024 17:56

I would like to inform you that a new version of Ab3d.DXEngine has been published.

This is only a bug fix release that fixes the problems that were found after the last release. What is more, a new Ab3d.DXEngine.glTF library was also published (see below).

Here is a list of fixes:

  • Fixed changing IsVisible property on InstancedTextNode.
  • Improved hit-testing by preventing the creation of new objects on each hit test.
  • Prevented exception when the IsVisible of DXViewportView is set to true (from false) but the size of DXViewportView is empty (0, 0).
  • Corrected calculating Bounds (BoundingBox) for ScreenSpaceLineNode and ScreenSpaceLineMesh when IsPolyLine is true. Before the bounds were too big because the 2 generated adjacency positions that were required by the shader were also counted into the BoundingBox.
  • Updated Bounds in ScreenSpaceLineMesh when calling RecreateMesh.
  • Added new overload to RecreateMesh method in ScreenSpaceLineMesh. The new overload also takes BoundingBox as a parameter. It can be used when BoundingBox is already known - this prevents calculating new BoundingBox from new positions.
  • Fixed regenerating screen-space positions in some cases when the count of line positions is changed.

As promised in previous blog posts, a new fully managed glTF importer for Ab3d.DXEngine was published. If you are showing 3D models in your application, then you will now be able to use the new glTFImporter instead of Assimp importer. This will remove the dependency on the native Assimp library. If you are currently using some other file format (for example, .fbx or .dae), then you may consider converting that to a glTF file. There are many offline and online glTF converters that can be used for that task.

First, note that the new importer can read only the second version of glTF files (version 2). This new version is also used by most of the 3D modeling tools. glTF files come with two possible file extensions: .gltf and .glb. The  .gltf file extension represents a text json file with basic information of the 3D objects. Usually .gltf file also comes with a .bin file that stores the vertex and index buffers and embedded textures. It is also possible to embed the buffers and textures as base64 encoded text into the .gltf file. The other possible file extension (.glb) represents a binary version of the file. It has a smaller size and is the fastest to read. It also contains all the buffers and textures.

glTF 2 files store materials by using PhysicallyBased properties that use base color, metalness and roughness as base material properties. Ab3d.DXEngine also supports showing PhysicallyBasedMaterials. But for technical and business 3D objects the material usually use diffuse and specular colors (StandardMaterial in Ab3d.DXEngine or DiffuseMaterial in WPF 3D). Because of this, the importer in the Ab3d.DXEngine.glTF library has two special properties that can be used to define when the StandardMaterial with diffuse color is created from the PhysicallyBased properties:

ConvertSimplePhysicallyBasedMaterialsToStandardMaterials - when this property is true (by default) then  simple glTF's PhysicallyBasedMaterials that have MetallicFactor set to 0 and do not have MetallicRoughness texture are converted into StandardMaterial objects.

ConvertAllPhysicallyBasedMaterialsToStandardMaterials - when this property is true (false by default) then all glTF's PhysicallyBasedMaterials are converted into StandardMaterial objects.

And here are a few screenshots from the sample models that can be downloaded from glTF sample assets (https://github.com/KhronosGroup/glTF-Sample-Assets):

ABeautifulGame 3D model importer by DXEngine's glTF importer

FlightHelmet 3D model importer by DXEngine's glTF importer

In the future, I plan to remove some of the library's dependencies by embedding the glTF objects model into the library. I will also add an exporter that will be able to export an existing 3D scene to glTF file.

Tags: , , ,

DXEngine

Great new features in new Ab3d.PowerToys and Ab3d.DXEngine

by abenedik 12. April 2024 11:22

Even though a new Ab4d.SharpEngine, a cross-platform rendering engine, was released a few months ago, work on the Ab3d.PowerToys and Ab3d.DXEngine has not stopped. The proof of that is the just published version that brings many great new features and improvements. Here is a list of the most important:

  • Added many new options to render pixels and point-clouds.
  • Added hardware support to render millions of textures as billboards.
  • Added support for Screen Space Ambient Occlusion (SSAO).
  • Significantly improved performance of line selection and generating edge lines.
  • Added sample that shows how to render objects with glow.

The previous version of Ab3d.DXEngine already provided great support for rendering pixels and point-clouds. It was possible to render millions of pixels with various sizes and colors. There was an OptimizedPointMesh class that could optimize the rendering of large point-clouds. On top of that, the new version adds the following new options:

  • The pixel size can be defined in screen or world size. Before, pixel size was defined only in screen size, but now you can also define the size in 3D world size so when using perspective camera the pixels that are farther away from the camera are smaller.
  • Pixels can be rendered as rectangles or as circles. Before, only rectangular pixels were possible. Now circular pixels can be rendered and this looks nicer for some point-clouds.
  • It is possible to specify a texture that will be rendered on each pixel. This can be used to render millions of billboards that are always facing the camera.
  • It is possible to fix the up vector of each pixel so the pixels do not fully face the camera. For example, this can be useful when rendering trees that are always growing vertically and should not face the camera when the camera is looking straight down.
  • The Ab3d.DXEngine samples project comes with new PlyPointCloudReader and PlyPointCloudWriter classes (available with full source code). They can be used to read and write point-clouds from and to ply files.

Here are a few screenshots:

Importing point-cloud with more than 12 million pixels from a ply file.

(Point-cloud with 12 million points)

Cropping point-cloud and exportin it to a ply file.

(New point-cloud importer sample supports exporting a cropped point-cloud)

Rendering may 3D textures as billboards (the screenshot shows 15.000 tree textures, but modern GPU can also easily handle many more textures).

(Rendering may 3D textures as billboards. The screenshot shows 15.000 tree textures, but modern GPU can also easily handle much more textures).

 

Another big new feature is support for Screen Space Ambient Occlusion (SSAO). If you look around you, you can see all the places around the room. All receive at least some light even if the lights or windows do not directly illuminate them. This light is called an ambient light. To correctly render that light, we need to use ray tracing. But in real-time computer graphics, we can usually specify an ambient light with just one value. This will illuminate all the objects in the scene with the same amount of light. But if you look around you, you will notice that, especially at the corners, the amount of ambient light is much lower, and a shadow is visible. Those shadows can be approximated by using the Screen Space Ambient Occlusion. This reduces the amount of the applied ambient light in places that have some objects around them.

See the difference in the following two screenshots (one with and one without SSAO):

Screen Space Ambient Occlusion (SSAO) that can dynamically shadow ambient light
SSAO disabled

Note that to see SSAO shadows, you need to use a lot of ambient light and should not use camera's lights (set camera.ShowCameraLight to ShowCameraLightType.Never). If you are using camera's light, it can illuminate the areas dimmed by the SSAO effect. So, using fixed directional or point lights and strong ambient light is recommended to see SSAO shadows.

 

The next major change in the new version is not a new feature but a significant improvement of the existing functionality that many of you are using. The new version of Ab3d.PowerToys greatly improves the performance of line selection and generating edge lines.

Showing edge lines can significantly improve the clarity of the shown 3D model. But with the previous version, if you had complex 3D models, calculating edge lines was very slow. The new version significantly speeds up this process. For example, the next graph shows the time in ms that was needed to generate edge lines for a complex P51 oil rig model (3.7 mio triangles; 1000 individual models, some have more than 100,000 positions; CPU: AMD Ryzen 9 5900X):

Graph that shows performance improvement of new edge lines generation

The previous version required 13 seconds in .Net Framework 4.8 (11 seconds in .Net 8). In the new version, this is almost 50 times faster: 350 ms in .Net Framework 4.8 (280 ms in .Net 8).

So, when using the previous version the user needed to wait for quite a while until the edge lines were generated, but now this is hardly noticeable.

What is more, if you know that your mesh is nicely defined or does not have duplicate positions, you can speed up this process even further. Duplicate positions are very common because they are required to create sharp edges by defining different normals for each position (for example, BoxVisual3D defined 24 positions and not only 6). But if you know that you have a smooth mesh without duplicate positions, you can set the ProcessDuplicatePositions property to false to skip the step of finding and collapsing duplicate positions. Also, if you know that the mesh has nicely defined triangles where each triangle edge is fully covered by any adjacent triangle edge (except on the outer mesh borders), then you can set the ProcessPartiallyCoveredEdges property to false. This skips code to process complex meshes (for example, such complex meshes can be produced by Boolean operations). If users of your application can import any 3D model, then you should have all the settings enabled, but if you have fixed 3D models, then you can experiment by turning off some settings and get even better performance. What is more, the updated "Edge lines creation" sample in Ab3d.PowerToys samples has code that shows how to easily write and read the calculated edge lines to and from a file.

 

Another very commonly used feature was line selection. The line selection in Ab3d.PowerToys allows selecting lines when the mouse is close to the line (the user can specify the max selection distance). When you were showing a lot of lines or lines have lots of line segments, then the line selection could eat a lot of CPU cycles. Before, 2D screen coordinates were calculated for all line segments. Then the 2D distance from the mouse to each line segment was calculated. The line with the closest distance was the result of the line selection. The new version significantly improves the performance of line selection for lines that have more than 30 segments. In this case, only 2D screen bounding box of the line is calculated and if the mouse position is in the bounding box or close to it, then the 2D screen positions for all line segments are calculated. This can skip a lot of calculations because only lines that are close to the mouse are fully processed. Note that to use the new faster code path, you need to set the new CheckBoundingBox property to true. This is needed to preserve the behavior of the GetClosestDistance method. Before, this method always returned a valid distance value, but now, when CheckBoundingBox is true and when the mouse position is not close to the bounding box, then double.MaxValue is returned.

What is more, if you are using ScreenSpaceLineNodes instead of lines derived from Visual3D objects (this significantly improves the initialization time but is harder to work with), then you can use the new DXLineSelectorData that is the same as LineSelectorData but works with Vector3 structs instead of Point3D structs. This will give you even better performance because of reduced memory usage (using float values instead of double values).

The following screenshot shows a new sample that shows 5000 lines each with 5000 line segments and still achieving super-fast line selection time:

Super fast line selection where lines can be selected by specifying the distance to the lines (moving mouse close to the line).

 

The next new feature did not need any change in the Ab3d.DXEngine library but it just needed a special rendering setup. It is implemented in a new "Glowing objects" sample that can be found in the Advanced section of the Ab3d.DXEngine sample project. As its name suggests, it shows how to render glowing effect to objects with an emissive material. I know that this is not an essential feature, but I am sure that some of you will be able to use it to achieve some very nice visual effects.

Rendering glowing objects.

 

As always, there were many other new features, fixes and improvements. You can check them by starting the updated sample projects (Ab3d.PowerToys or Ab3d.DXEngine) and checking for samples with NEW or UP icons. You can get the list of all changed in Ab3d.PowerToys change log and Ab3d.DXEngine change log

 

When speaking about fixes, I would like to mention one nasty bug that occurred when many 3D lines were rendered (using multi-threader rendering), and after the size of the window was changed, then in some cases the lines could be rendered with invalid line thickness. If this also happens in your application, then please upgrade to the latest version. If this is not possible, then disable multi-threader rendering for 3D line or the whole scene (contact support for more info).

 

Lastly, I would like to mention that the new version comes with a new native Assimp importer that can import 3D models from many 3D file formats. The previous official version of Assimp importer v5.3.1 was released more than half a year ago (2023-09-25). The new version was released just a few days ago (2024-04-07) and comes with many improvements (https://github.com/assimp/assimp/releases). You can build the new version by yourself or get prebuilt dlls from the libs folder in the Ab3d.PowerToys or Ab3d.DXEngine samples.

 

Here, I would also like to announce that in the coming weeks, I will be releasing a fully managed glTF importer and exporter. This will allow you to import 3D models with full details without using a native Assimp library. Currently, if you do not want to use Assimp importer, you could use ReaderObj (part of Ab3d.PowerToys library) to read obj files or use Ab3d.Reader3ds library to read 3ds files. However, both obj and 3ds file formats have their limitations. Obj files do not support hierarchy and animations, are text only, and have limited materials. 3ds files support only 8.3 file names for textures. So, those two file formats could be used only in a limited number of cases.

On the other hand, the glTF 2 file format is a modern file format that was developed by Khronos group and can store meshes, hierarchies, materials, transformations and animations in a text or binary format. Suppose you distribute 3D models with your application and are currently using Assimp importer to load the models from various files. In that case, you will be able to convert the files into glTF (using Assimp importer and exporter or by using some other third-party or online glTF converter) and then distribute your models as glTF files. This way, you will not need to distribute native Assimp's dlls with your application anymore.

 

As seen here, the new version can significantly improve the performance of your application and the new features can make it even more visually appealing.

Now, the primary development focus will switch back to the new Ab4d.SharpEngine. I am really happy with the adaptation of the new engine. It seems that the first version already had enough features for many of your projects. Some new features have already been developed, but many are still to be implemented. I am planning to publish a new version in June 2024. So, if you have any feedback or a new feature request for the new version, now is the best time to provide that.

Tags: , , ,

Ab3d.PowerToys | DXEngine

New Ab3d.PowerToys and Ab3d.DXEngine version published

by abenedik 14. December 2023 16:06

New maintenance release for Ab3d.PowerToys and Ab3d.DXEngine has been published.

The new version does not come with any bigger new features and only brings a few fixes and improvements. Because of this, only the build version was increased, but the major and minor versions remained the same.

This version also comes with a new build for .Net 8.0. .Net 8.0 that was released a few days ago. At that point, I would like to thank the .Net team, which is doing a great job with each new .Net release. For example, the last version again came with many new performance improvements - see the article about that: Performance Improvements in .NET 8. This means that without any changes in the code, your code will run faster just by using the latest version of .Net.

I did a quick performance test by running the DXEngine multi-threading sample in .Net framework 4.8 and then in .Net 8.0. I used only single-threaded rendering with disabled commands caching and by showing 160.000 3D boxes and 3D lines. This means that for each frame the engine needed to set shader states and issue 160.000 draw calls. The results were astonishing. When running in .Net framework 4.8, the code required around 47 ms to render one frame. But when using .Net 8.0, only around 33 ms was needed for the same job. This is a 30% performance improvement. 

Ab3d.DXEngine performance in .Net 8.0

The new version also comes with an updated Assimp importer. There is a new native Assimp library (v5.3.1) and a new managed Ab3d.PowerToys.Assimp library. Using a newer native library provides a more accurate importer and can read more files correctly. On top of that the Ab3d.PowerToys.Assimp was also improved. This version adds support for reading files with non-ASCII file names. Also, now it is possible to read diffuse textures with emissive materials. And in case you were using hardcoded object names, then I need to inform you that the new version also comes with a breaking change because the new version may set the object names differently. The latest version tries to use names so that they are as close to the original name as possible. In case when an object group also defines its own meshes, the previous version set the name of the Model3DGroup by adding the "__Group" suffix. The new version set the Model3DGroup's name to the original name without any suffix. To prevent using duplicate names, it adds a mesh name as a suffix to the GeometryModel3D's name that is added as a child of the Model3DGroup. If you want to preserve the previous naming, then set the PreserveGroupNames property to false. Note, then in WPF, an object's name must start with a letter or underscore and can contain only letters, digits, or underscores. Because of this, the object names may still be different from the original names in the file. For example, "12-material#10" would become "_12_material_10".

The updated Assimp importer files can found in the libs folder on GitHub.

To see the list of other fixes and changes, see the change log web pages: Ab3d.PowerToys history and Ab3d.DXEngine history.

As mentioned last week, when the new SharpEngine was released, I am planning to release a new major version of Ab3d.PowerToys and Ab3d.DXEngine at the end of Q1 2024 . The following are planned new features:

  • Add support for Screen Space Ambient Occlusion (SSAO) - this can significantly improve the visual quality.
  • Add new options to render pixels and point clouds (world-size pixels in addition to screen-size; render circular pixels or pixels with custom textures).
  • Add support for rendering 3D lines and line segments to an object ID bitmap (can be used for faster line hit testing; especially for MultiLineVisual3D).
  • Add options to copy only part of the object ID bitmap from GPU memory to CPU memory - this would make using ID bitmaps for hit objects much faster.
  • Trying to improve the performance of calculating edge lines by using oct-tree.

For 2024, I would also like to introduce a new product that would allow importing 3D models from STEP and IGES file formats that are commonly used by CAD applications. Later, there would also be improved support for geometric and surface modeling that is based on mathematical surfaces and not triangles.

If you have any additional requests or wishes, please contact us. Otherwise, stay tuned.

Tags: , , , ,

Ab3d.PowerToys

Major versions for Ab3d.PowerToys and Ab3d.DXEngine published

by abenedik 5. July 2023 20:27

I am happy to inform you that new major versions of Ab3d.PowerToys and Ab3d.DXEngine have been published.

The new release brings many great new features and one bigger breaking change.

The breaking change is the removal of the ViewCubeCameraController:

ViewCubeCameraController

A customer recently informed me that the ViewCube is patented by Autodesk. It seems that the patent is active only in the USA. See here: https://patents.google.com/patent/US7782319

Therefore I have decided to remove that control from the library. Instead of ViewCubeCameraController the new version of the Ab3d.PowerToys library now provides the CameraNavigationCircles control. See the screenshot of the new sample that demonstrates the CameraNavigationCircles:

CameraNavigationCircles Sample

 

And an animation showing that control in action:

CameraNavigationCircles animation

As you can see, the new control provides many customization options and can be used in many different ways. What is more, it can replace both ViewCubeCameraController and also CameraAxisPanel.

However, if you are already using the ViewCubeCameraController and would like to continue using it, then please first carefully study the patent, and consult with a layer. If you still want to use the ViewCubeCameraController, then please contact me and I will send you the source code for that control so you will be able to integrate it into your project.

 

Another major new feature of this release is improved support for line caps (line endings). Previous versions supported only arrow line caps. The new version adds support for additional arrow types, boxes, diamonds and circles. See the screenshot from the new sample that demonstrates that:

3D lines with different line caps

What is more, the Ab3d.DXEngine finally gets full hardware acceleration of all 3D lines, including lines with line caps. Before, lines with line caps were generated on the CPU (on each camera change the MeshGeometry3D of the line was regenerated and this was very slow). The new version solves that and moves the generation of the lines to the geometry shader. This means rendering millions of 3D lines with different line caps is now possible.

The new Ab3d.DXEngine also improves line initialization time, so if you define many 3D lines, the engine will show them faster. Also, the order in which lines and other 3D objects are rendered is defined by an improved sorting mechanism, so there should be fewer DirectX state changes when rendering, resulting in slightly faster rendering.

The new release also comes with a new build of native Assimp library that can be used to import 3D models from almost any 3D file format. Unfortunately, it seems that the version number of that library has been stuck at v5.2.5 for almost a year, regardless of hundreds of commits. To still be able to see what version is used, a new GitCommitHash property was added. It returns the Git commit hash of the version. For example, the Assimp library that comes with this release has GitCommitHash set to 0dcfe2f - from 2023-07-03. 

The new Ab3d.PowerToys.Assimp library now also supports reading lights and camera data from the imported file.

 

There are also many other improvements and fixes. Even though a lot of time was spent on the new Ab4d.SharpEngine, the list of changes is still very long - see the change logs for Ab3d.PowerToys and Ab3d.DXEngine.

Tags: , , , ,

Ab3d.PowerToys | DXEngine

New Ab3d.PowerToys and Ab3d.DXEngine with .Net 7 build

by abenedik 10. November 2022 19:58

New versions of Ab3d.PowerToys and Ab3d.DXEngine have just been released. The new versions bring many great new features and because they were released just after the .Net 7 release, the new versions also come with a new .Net 7 build.

Because this release is also linked to a new .Net version release, this blog post also shows some performance numbers related to running Ab3d.DXEngine by using different .Net versions. See the end of this blog post for more information.

 

Now back to new features. In the past there were many requests to improve the triangulator that was part of the Ab3d.PowerToys library. If we want to show a filled 2D shape, for example an ellipse, as a 3D object, we need to first convert 2D points to 3D points and then define the triangles that will connect the positions. This can be done by using a triangulator. The old version of Ab3d.PowerToys already has a triangulator, but it could process only simple polygons. This was improved in the new version so that the new triangulator can now process multiple polygons and also supports polygons with holes.

Triangulated 3D text

As seen from the image above, this allows generating a 3D mesh from any text (text is represented by a series of 2D shapes). The sample also shows how to generate a 3D mesh from multiple 2D shapes (ellipses, rectangles, paths with bezier curves, etc.). The lower part of the sample shows individual triangles that were generated. There is also a Slider control that can be used to show how the triangles are laid out from the first to the last.

In some cases the new triangulator can also be used instead of Boolean operations. This requires that the main 3D object has a constant height (for example represents a sheet of metal or wood). In case when user wants to subtract a cylinder or some other object that can be extruded from a 2D shape, then using the triangulator instead of a Boolean subtract operation will be much faster and will provide better results (fewer triangles will be created).

Another highly requested feature is better support for collision detection. By using bounding boxes it was already possible to do some collision detection. However, because the bounding box is only an approximation of the space occupied by the object, this was not very precise. The new version of Ab3d.DXEngine brings a new MeshCollider object that can be used to check if one 3D position is inside another 3D mesh. By checking all the positions of one mesh, it is possible to check if one mesh collides with another mesh. The new sample demonstrates that (when checking the sample use arrows, PgUp and PgDown keys):

MeshCollider

An interesting new material type that will greatly simplify work for some users is the new FaceColorMaterial. It supports defining different colors for each of the triangles in the mesh. Before it was already possible to achieve that by using a VertexColorMaterial. But this required that the positions of the mesh were duplicated so that each triangle used its own unique set of positions. Now this is greatly simplified because the original mesh can be used. What is more, by setting the alpha color to zero, the individual triangles can be discarded from rendering. The new sample nicely demonstrates that:

Face color material

Improving the performance of the Ab3d.DXEngine is a never-ending job. This version brings two new performance improvements. The first one is for those that use DXEngine's SceneNode objects and meshes. The new version significantly improves performance of hit testing because it can use OctTree objects on DXEngine's meshes. Before OctTree objects were created only from WPF's MeshGeometry3D objects. 

OctTree object organizes the triangles in a mesh in hierarchically organized 3D space regions so that when triangles are checked if they are intersected by a 3D ray, the number of checked triangles is much much lower. This makes hit testing almost instant even on huge meshes.

Now the DXScene.DXHitTestOptions.MeshPositionsCountForOctTreeGeneration property is also used when doing hit tests on DXEngine's meshes. Its default value is 512. This means that an OctTree will be automatically generated when the mesh has more than 512 positions. You can also manually generate the OctTree by calling the CreateOctTree method.

The second performance improvement will be great news for those who are rendering many polylines (lines where line segments are connected to each other). Multiple polylines are usually defined by a single MultiPolyLineVisual3D object. But though one object is used to define multiple lines, each line was still rendered by its own DirectX draw call. And if there were thousands of lines to render, it took quite some time to issue draw calls for each line. The good news is that with the new version, all the polylines can be rendered with only one draw call. This means that there will be almost no CPU cost for rendering any number of polylines.

As always, there are also many other improvements and fixes. See the change logs for more details here: Ab3d.PowerToys changelog and Ab3d.DXEngine changelog. Also get the latest samples (Ab3d.PowerToys.Wpf.Samples and Ab3d.DXEngine.Wpf.Samples) and check for UP and NEW icons to see new or updated samples.

 

And as promised before, let me show you some additional performance numbers. Each .Net version brings many performance improvements. There are new classes that can be used to write faster code. But also existing .Net code can run faster because each version improves the JIT compiler so it produces faster assembler code. The following graph shows how performance of the Ab3d.DXEngine can be improved when the application is run in a newer .Net version (running in .Net 4.8 is shown with a blue rectangle that represents 100% of the time; running in .Net 6.0 and .Net 7.0 executed the code faster and therefore the rectangles are shorter):

Ab3d.DXEngine performance in .Net versions

(1) "Multi-threading and caching" sample was run with showing 20000 boxes, using no background threads and disabled DirectX caching. The DrawRenderTime performance parameter measures the time that Ab3d.DXEngine needs to issue all DirectX draw calls. This requires going through all objects, checking their state, setting the DirectX state and calling DirectX Draw method. In this sample most of the time is spent in native DirectX code so the performance gains cannot be huge. But still, there is almost 10% better rendering performance just by using a newer .Net version.

(2) "Instanced animated arrows" sample was run with showing 1 million arrows. The graph shows values for the time that is required to calculate 1 million transformation matrices - each matrix is defined so that an arrow mesh will point toward the animated sphere. The values are based on highly optimized code (manually inlined and optimized math operations) that run on multiple threads (using Parallel.For).

(3) "Instanced animated arrows" sample showing 1 million arrows but this time the source code without any manual optimization is executed. The graph shows that the new JIT compiler can greatly optimize the generated assembler and in this case can provide a 25% performance boost.

(4) "Transparency sorting performance" sample shows the performance of different sorting algorithms that sort 3D objects to prevent transparency artifacts (the sample was updated to show 7200 instead of 720 boxes). The values under (4) show the difference of sorting that sort WPF 3D objects and is implemented by TransparencySorter from Ab3d.PowerToy library. Working with WPF objects is not very fast and there will be no changes in the WPF to make this faster. So it is great news that only using a new version of .Net can significantly improve the performance.

(5) The values here are again from the "Transparency sorting performance" sample, but this time showing the performance improvements of the transparency sorting from Ab3d.DXEngine. The source code for this sorting algorithm is already highly optimized, but still newer versions of .Net can squeeze some more juice from that.

So, Microsoft, keep up the great work!

 

And finally, the first open beta version of the new Vulkan based cross-platform rendering engine will be available before the end of this year! Let's conclude with the new logo for the engine:

Ab3d.SharpEngine logo

Tags: , , , , , ,

Ab3d.PowerToys | DXEngine