SDK 1.10.13 Release

‘Tis the season for another Panda3D release! This is quite an important release that comes with a bunch of important stability improvements and bug fixes, but also introduces a bunch of interesting features that I am excited to tell you about. I am just going to highlight a couple of changes below, the full list can be found in the release notes on the download page.

Bugs on macOS

A series of issues relating to the macOS support have been addressed. Some issues were present with newer M1-based Macs, such as a black screen when switching to full screen mode, a crash when enabling the multi-threaded render pipeline, and an error loading the module. These issues should now be resolved. Furthermore, pressing Command+Q now no longer immediately kills the application, but sends any registered close-request events (allowing the operation to be cancelled) or otherwise still causes exit functions to be run.

Motion Trails

A screenshot of the new sample program

Panda3D contains a sophisticated geometry-based motion trails generator, which allows easily creating a wide range of interesting effects that involve extruding geometry behind an object’s path. Both a Python-based and C++-based implementation are available. However, this feature wasn’t documented at all, presenting a significant barrier to its use.

Due to a user need, this module has been dusted off and documented in the API reference. Furthermore, some substantial performance optimizations have been made. A sample program has been graciously provided by community member Entikan and is now included with the distribution.


The performance monitoring tool PStats has received some improvements. Importantly, a crash on start-up has been fixed that started occurring after recent updates on some Linux distributions. But the most major improvement is the ability to integrate with the Python profiler and measure the performance cost of all functions invoked by Python code. This provides a much more fine-grained view of Python code, which was previously only measured on a per-task basis. All you have to do is enable pstats-python-profiler in Config.prc, and you can see the performance of your code on a per-module level, then drill down all the way to the individual classes and functions.

Please note that due to the extra cost of instrumenting every single Python call and the increased amount of data being transmitted by PStats, this feature does add a performance overhead depending on how many Python calls are being made in your program. It is therefore recommended to only enable this feature once you’ve established that the Python code is a significant bottleneck in your application. However, some performance optimizations were made to the PStats client and server to partially mitigate this overhead. More invasive optimizations have also been made on the master branch and will follow in Panda3D 1.11.0.

Apropos, even more significant improvements to PStats will follow in Panda3D 1.11.0 that make this feature even more useful, such as new graph types that can show the entire call graph of an application at once, seamlessly interleaving Python function calls with existing PStats collectors. Stay tuned for more information about this! The screenshot below provides a little sneak-peak at what this will look like:

Deployment System

A number of improvements have been made to build_apps. Firstly, the code was compiled with an inconsistent optimization level. Now, all code is built with optimize level 2. This also removes any docstrings (__doc__ will always be None), but if you need to retain those, you can set the new keep_docstrings option to lower the optimization level down to 1. Note that the optimization feature is only supported in Python 3.2 or higher; older versions still depend on explicit -O or -OO flags being passed to the interpreter.

On Windows, it is now possible to force a dedicated NVIDIA or AMD video card to be selected on laptops that feature both an integrated and dedicated GPU. To enable this feature, set the prefer_discrete_gpu option. This is accomplished by compiling a special symbol into the .exe file, which is the only way to force the driver to choose a particular GPU. This is why this is a flag that had to be added to the deployment system and not a configuration flag in the Panda library itself.

Finally, the experience for automatically converting models to .bam has been improved. Presently, a default handler is registered that automatically invokes egg2bam on any included .egg models, but this mechanism could be slow (as it doesn’t use the already converted models in the model-cache) and doesn’t support extensions other than .egg, such as .gltf. You can now use the new bam_model_extensions option instead, which is a list of extensions that will automatically be converted via the new mechanism. Any model format that can be loaded by a loader plug-in is supported. Here is an example for glTF files, assuming that the panda3d-gltf plug-in has been installed:

options = {
    'build_apps': {
        'include_patterns': [
            # Make sure the gltf/glb file is being found
        # Models with these extensions are converted to .bam automatically
        'bam_model_extensions': ['.gltf', '.glb', '.egg'],

CommonFilters and MSAA

Close-up of the Cartoon Inking sample showing the effect of MSAA

Applications that use CommonFilters for post-processing effects now have a more specific method of enabling multisample anti-aliasing, via a newly added “MSAA” filter. This is not in fact a filter, but a convenient way to enable multisample anti-aliasing on just the offscreen buffer that this class renders the scene into. Previously, it was necessary to enable MSAA for the main window, which would make this automatically enabled for the buffers created by CommonFilters, but now you can enable it specifically for the offscreen buffer. This means you should not put framebuffer-multisample in your Config.prc file, but rather just call setMSAA on the CommonFilters object. This accomplishes the following:

  • Less video memory is used, since the main window framebuffer does not need storage for the additional samples.
  • You can change the MSAA setting without recreating the main window, which is useful when changing this on-the-fly via an in-game Settings menu.

In addition to this change, a bug has been fixed when using MSAA in conjunction with multiple render targets, which is a feature that is used for effects like cartoon inking.

Assimp Plug-In

There have also been updates to the Assimp loader plug-in, which leverages the Assimp library to support importing a wide range of asset formats. Some bugs have been fixed and additional features have been added, including support for custom object properties, additional texture maps (including PBR-based ones, compatible with panda3d-simplepbr), texture transforms, tangent and binormal vectors, and more.

Capsule-Polygon Collision Test

It’s a hit!

By user request, it is now possible to use capsule shapes as a “from” object when testing for collisions with polygon objects. This completes the set of intersection tests for CollisionPolygon, meaning that all valid “from” solids now have an intersection test defined into CollisionPolygon.

At this time, there is not yet support for the respect-prev-transform mechanism, meaning that collisions are not detected when the capsule moves so fast that it never comes in direct contact with the polygon. It is therefore still recommended to use a sphere instead of a capsule whenever possible. This restriction may be lifted in Panda3D 1.11.0.

Removing Textures and Materials

Previous versions of Panda3D have added the replace_texture() and replace_material() methods to the NodePath class, which allow recursively replacing a known texture or material with a different one in all underlying scene graph nodes. However, it was not so easy to remove a texture or material recursively. There is of course set_texture_off(1) and clear_texture(), but the former doesn’t really remove the texture, whereas the latter does remove it but only does so from the current node, not from any child nodes.

Therefore, a change has been made to allow None to be passed in as second argument of replace_texture() and replace_material(). Doing so will recursively remove the given texture or material from the entire branch of the scene graph.

OpenSSL 3

The encryption functions in Panda3D would no longer work when building with OpenSSL 3. This is because Panda3D is using Blowfish (bf-cbc) encryption by default, but this cipher is deprecated in OpenSSL 3 and has to be specifically enabled by loading the “legacy” provider. This issue has been fixed, as Panda3D will now automatically load the legacy provider when using this encryption scheme.

That said, we do recommend switching to a non-deprecated encryption scheme, such as AES-256. This can be done by setting the following in Config.prc:

encryption-algorithm aes-256-cbc

This will become the default in Panda3D 1.11.0. Note that changing this setting does not affect compatibility with other builds of Panda3D, because the decryption code in Panda3D automatically detects which algorithm is being used.

Other Changes

This release contains many other improvements, some of which are listed below:

  • There was a race condition when creating and destroying NodePath objects on separate threads, which is now fixed.
  • The shader generator (and any custom shaders using the attr_fogcolor input) now properly update with fog color changes.
  • copy.deepcopy() is now supported for both Texture and PointerToArray objects, which are now ensured to have their underlying storage completely uniquified.
  • Some erroneous mouse event behavior that would occur when the mouse pointer leaves the window has been resolved.
  • When calling flatten_strong(), nodes with texture transformations (TexMatrixAttrib) would not always have this transformation flattened to the model’s UV coordinates in situations where this was possible. This is now resolved.
  • Calling Notify.ptr().set_ostream_ptr() to override the stream used for logging in Panda3D no longer requires a reference to the stream to be kept in the Python code to avoid a crash.
  • When writing double-precision floating-point values into a color column with GeomVertexWriter, these values are now clamped to the 0..1 range, the same way as they would for single-precision floats.
  • The Parallel-Split Shadow Mapping (PSSM) feature from the panda3d._rplight module no longer fails to work properly when setting the far distance on the camera lens to infinity.
  • ConfigVariableFilename objects now support the os.fspath() protocol, and can therefore be passed to anything that accepts an os.PathLike.
  • Deprecation warnings are no longer displayed when copying an OdeTriMeshGeom object.
  • A workaround has been introduced for misbehaving window managers on Linux (such as swaywm) where the window would remain black until moved or resized.
  • A bug in the OpenGL renderer has been fixed where custom GLSL shaders could read incorrect values from vertex attributes after rendering an object with hardware instancing.
  • When gl-version 3 2 (or higher) is set in Config.prc, the number of texture stages available to custom GLSL shaders was being limited to 1, which also prevented access to secondary texture coordinate sets. This limit was unintended and is now removed.
  • Some bugs have been fixed relating to the use of render-to-texture in combination with the multi-threaded rendering pipeline.
  • The #pragma include <file.glsl> syntax, with angle brackets instead of double quotes, is now working properly in GLSL shaders.
  • ExecutionEnvironment.args is no longer empty on Linux.
  • An assortment of functions to query additional properties of the interrogate database has been added to the panda3d.interrogatedb module.
  • The GarbageReport module is no longer broken in Python 3.
  • The nested_vertices property of PandaNode would sometimes erroneously contain 0. It is now updated properly.
  • As an optimization, Panda no longer recalculates the bounding volume of Geom objects which already have a custom bounding volume set.

Head to the download page to try out the new release or read the full release notes. As usual, don’t hesitate to share your thoughts about the changes and file issues in the issue tracker if anything isn’t working as it should.