KK Physics

Following a discussion in this forum, I began developing a physics library for JME based on Jolt Physics. It’s called “KK Physics”, and a pre-release version was published today.

The goal of KK Physics is to bring modern, high-performance physics to JMonkeyEngine. For various reasons, it mimics the APIs of Minie and jme3-jbullet as far as possible. However, I doubt it will ever be a drop-in replacement for either of those libraries.

Today’s pre-release features:

  • static and dynamic rigid bodies with friction and restitution
  • 4 collision shapes (box, Y-axis capsule, Y-axis cylinder, and sphere)
  • BulletAppState and RigidBodyControl
  • debug visualization
  • PhysicsDumper and PhysicsDescriber

It depends on:

  • Java 19 preview
  • jme3-core v3.6.1-stable
  • jolt-java v0.1.0
  • sim-math v1.6.0
  • Heart v9.1.0

Excluding blanks and comments, KK Physics is about 4,800 lines of Java. In contrast, Minie is currently about 73,000 lines of Java, so it’s clear many features are missing. Among them:

  • support for Android, macOS, and Windows
  • compatibility with JVM languages other than Java 19
  • many collision shapes, including compound, cone, convex hull, gimpact, heightfield, mesh, multisphere, plane, and simplex
  • characters, ghost objects, soft bodies, and vehicles
  • kinematic rigid bodies
  • physics joints and ragdolls
  • continuous collision detection (CCD), linear/angular damping, linear/angular factors
  • collision/contact listeners
  • cloning and serialization
  • ray casts and sweep tests
  • approximate convex decomposition
  • tutorials and automated tests

Despite all these constraints, v0.1.0 has proven adequate for porting 5 Minie applications.

Instructions are found in the project’s README.

For the next release, I hope to find or develop a direct JNI interface to Jolt Physics v5.0.0, to replace jolt-java (which uses jextract on an incomplete C API). Switching to direct JNI should resolve many current limitations of KK Physics, but I don’t know how long that will take.

While it’s possible KK Physics will someday replace Minie, I plan to continue maintaining and improving Minie for the foreseeable future.

22 Likes

Thank you v much for your work !!

1 Like

One thing to consider is starting to use Java Foreign Function and Memory API (FFM, JEP 454: Foreign Function & Memory API), which in my understanding is replacing JNI.

Of course the downside is that Java 21 is the latest LTS (long term support), and FFM is only available as preview there. Java 22 is the version where it was released as final. Java 22 is already out, but it is not LTS. There is probably no good reasons to be conservative like me and stick to the LTSs. Especially here it feels like JNI would be writing legacy code from the get-go…

I have never tried neither JNI or FFM so my expertise is rather limited. But I thought that this would be nice to know at least.

Either way, nice work!

5 Likes

Thank you for that suggestion. I will try using FFM and see how it compares to JNI in practice.

3 Likes

I’m quite impressed by what I’ve seen with the FFM API, and I definitely would use it where possible going forward. However, one thing to note here is that it only supports linking to C APIs - since Jolt is C++ (and since @sgold mentioned its C interface isn’t kept up well let’s pretend for the sake of discussion that the C API doesn’t exist), there still needs to be a C++ → C interface layer that gets written. Personally, I’d probably write a generic (non-JNI) interface and bind to it with the FFM API.

4 Likes

Writing a C++ to C layer seems like a lot of work, particularly for Jolt Physics, which employs C++ tricks such as inheritance and templates. In particular, I would think going through a non-OO langauge would make it harder for a JVM library to mimic Jolt’s class hierarchy.

On the JNI front, I’m making good progress. If anyone cares to follow along, I’m working in the following GitHub repo:

12 Likes

After 9 days of focused effort, the JNI bindings finally reached an acceptable pre-release, so now I’m once again working directly on KK Physics.

Already, it is much improved:

  • It no longer depends on Java 19 preview. Plain old Java 11 or later works just fine.
  • I believe it works on the “big four” platforms (Linux64, MacOSX64, MacOSX_ARM64, and Windows64) instead of just Linux64, though I still need to verify this.
  • Debug visualization is far more efficient than it was in KK Physics v0.1.0 .
  • App developers can easily trade off platform support against application size.
  • App developers can easily switch the native libraries between Debug and Release builds and between single-precision math and double-precision math.

Performance is great, but I see this still as a proof of concept, not a product. One known issue is that it doesn’t automatically free native memory!

My plan is to see what KK Physics can achieve using jolt-jni v0.1.10. Once I encounter diminishing returns, I’ll publish KK Physics v0.2 and turn my attention back to improving jolt-jni.

The FFM experiment remains hypothetical for now.

13 Likes

There were a few issues with macOS, but those are solved now.

Since the goal of KK Physics is to boost performance, I ran a new batch of comparisons across all 3 major desktop operating systems, comparing KK Physics latest “master” to Minie latest “master”.

All tests used the “TestManyBoxes” app, “Release” single-precision native libraries, CCD disabled, one physics step per frame, JMonkeyEngine v3.6.1-stable, LWJGL3 displayed in a window with Vsync and gamma correction enabled. All tests had assertions disabled.

The Minie tests all used AXIS_SWEEP_3 broadphase acceleration.

The performance metric was the number of boxes simulated at 30 frames per second, reported as the range of 3 separate runs. (Larger numbers indicate better performance.)

  1. Mac Mini M1 with 8 GiB RAM running Zulu JDK 11 on Ventura 13.2.1
    (a) Minie single-threaded: 3618 - 3676 boxes
    (b) KK Physics with 7 worker threads: 3885 - 3930 boxes (6% - 9% more boxes)
  2. HP Omen laptop (i7-1075H @ 2.6 GHz) with 32 GiB RAM and GeForce RTX 2070 running OpenJDK 17 on Linux Mint 21.3 Edge
    (a) Minie single-threaded: 2821 - 2885 boxes
    (b) KK Physics with 11 worker threads: 3458 - 3497 boxes (20% - 24% more boxes)
  3. Same HP laptop running Adoptium JDK 17 on MS Windows 11 Home 23H2
    (a) Minie single-threaded: 2797 - 2882 boxes
    (b) KK Physics with 11 worker threads: 3452 - 3734 boxes (20% - 33% more boxes)

Notes:

  • 25% more boxes doesn’t imply that the physics engine is only 25% more efficient. In the worst case, simulation work increases as the square of the number of bodies.
  • I haven’t made any effort to equalize the C++ compilers and their optimization options.
  • I need to investigate the impact of varying the number of worker threads on KK Physics.
  • I need to investigate what’s limiting performance and do more tuning, especially for KK Physics.

So far, KK Physics performance is looking good. Not as great as I’d hoped, but good enough to motivate further development.

14 Likes

Great work so far.
To me personally 20% sound like a lot for something that for me is a big O limited “feature”.

1 Like

Amazing work @sgold !
It’s not easy to be focused on a side-adventure task for such long period of time…

1 Like

Amazing work @sgold !
It’s not easy to be focused on a side-adventure task for such long period of time…

Thank you, @adi.barda.
I regard KK Physics as potentially a 3-year project. I hope it won’t stay at the current level of intensity, however!

With PauseOnLostFocus set to false, I used VisualVM v2.1.8 to collect CPU profile data from the final 21 seconds of a TestManyBoxes run that reached 3466 boxes. Here are the CPU time percentages for the “heavy hitters” in the “jME3 Main” thread:

  • 78.9% in PhysicsSystem.update() [*]
  • 10.1% in RenderManager.renderViewPort()
  • 3.8% in PhysicsSystem.optimizeBroadPhase() [*]
  • 2.9% in Node.updateGeometricState()
  • 1.9% in Body.getCenterOfMassPosition() [*]
  • 1% in Body.getRotation() [*]
  • 0.5% in Spatial.worldToLocal()
  • 0.5% in Spatial.getWorldRotation()

With 99.6% of the thread’s CPU time accounted for, it spent 85.6% of the time in 4 physics methods (starred) that are essentially Jolt native code.

Currently optimizeBroadPhase() is invoked on every frame. There’s potential to reduce that frequency, but the data shows it won’t have a large impact on this workload. Hacking the library, I reduced the frequency to every 3rd frame, and the impact was barely measurable: about 1% more boxes.


Another interesting data point: reducing the number of worker threads from 11 to 1 limits the number of boxes to about 2300, which is about 82% of what single-threaded Minie supports.

Admittedly, TestManyBoxes is a simplistic workload. Somehow Jorrit Rouwé measured Jolt having 3x better single-thread performance than Bullet on a ragdoll workload. I hope KK Physics will someday show similar benefits over Minie on some workload.

9 Likes

Time for a progress report.

Most of my recent effort has gone into jolt-jni, the low-level library that provides JNI bindings for Jolt Physics. It’s still incomplete, but there’s a new release (0.3.0) that I think might be suitable for beta testing. It supports simulation of rigid bodies (including static and kinematic ones) with various shapes. Automatic freeing of native memory is now available as an option. I’ve settled on an approach for coping with Jolt’s reliance on C++ templates, so I think future development will go more smoothly.

A to-do list for jolt-jni:

  1. convex radius (similar to Bullet’s collision margin)
  2. compound shapes
  3. rotated-translated shapes
  4. character controllers
  5. contact and activation listeners
  6. ray casts
  7. constraints/joints
  8. soft bodies

Aside from the javadoc, jolt-jni doesn’t have much documentation yet. If you’re interested in testing jolt-jni, let me know, and I’ll write some instructions to get you started.

The KK Physics library (which provides a Minie-like API on top of jolt-jni) has made some progress, though less than I’d hoped. There are fundamental differences between Jolt Physics and Minie that are difficult to bridge, even for rigid bodies. I’ll keep working on it.

15 Likes

I have not read the full thread, so excuse me if my knowledge weren’t up-to-date regarding this thread. There is JNA (Java Native Access) that is built on top of JNI afaik, but for some software design it removes the burden of writing JNI code, in any case I have to share it in case it helps but for credibility, I really haven’t tried or tested it and I don’t know how it behaves regarding shared memory and memory manipulation.

EDIT:
This is the general vision in case you would like to have more technical information in-mind:

1 Like

Thanks. I was aware of JNA, though I’ve never used it. If I understand correctly, it has the same difficulties with C++ templates that Panama/FFI has: one must write wrapper code in C. If I’m going to write wrapper code for every function, I may as well use JNI, with which I have 7 years experience, and write it in C++, an object-oriented language.

Java documentation often refers to “native code”, lumping together C and C++. But as you’re doubtless aware, there are huge differences between C and C++, just as there are huge differences between C++ and Java…

1 Like

Good Luck! Btw, if you are looking for a standalone library for loading native binaries, you could try jSnapLoader, the project is still at its alpha, however, I have tested it on Linux, Windows, and Android up till now:

EDIT:
The library is very minimalistic and utilizes Java IO APIs, and is based on a simple hierarchial pattern, so that system-specific actions are encapsulated directly without additional indirections.

1 Like

What are the advantages of jSnapLoader over the NativeLibraryLoader utility that’s built into jme3-desktop?

1 Like

I haven’t got a wide exposure to the JME3 native library loader, apart from a review on a PR in jme-3.7.0 as far as I remember, so I cannot give a comprehensive comparison. However, all I know is that it is not intended for public use, so typically designed primarily as an internalized structure.

As for jSnapLoader, the primary design was ad-hoc, and was deemed to provide something similar to the JME3 native loader, but for a finer version. By time, I had separated the API to be standalone for other Java Native Interface Applications. The current design essentially decomposes the library job into its main constituents: Compressed Locator - Platform detection - File Locator - File Extractor - Buffered Byte Stream - Native Library Loading. So it typically adds abstractions for all these constituents, in other words, it could operate on any compressed filesystem (only tested on ZIP and JAR!) and is not essentially tied to native libraries, it could extract assets, as well. (EDIT: It was a part of Serial4j, as well before separation).

Here is an exhaustive feature list:

  • Platform detection.
  • Extracts and loads native libraries from the stock jar library (classpath).
  • Locates external jars, extracts and loads native platform-specific libraries from them.
  • Define an extract directory.
  • Anti-failure mechanisms: Retry Criterion with clean extraction (NEW).
  • Extraction listeners: Extraction completed listener.
  • Utilities: Exposed the platform-dependent library NativeDynamicLibrary (NEW).
  • Utilities: Exposed the NativeVariant providing a utility for system properties.
  • Others: Extraction of files from compressed files.
2 Likes

it is not intended for public use, so typically designed primarily as an internalized structure.

JME’s native library loader pre-dates my involvement in the project, so I can’t speak to whether it was intended for public use. However, it’s a public API, and in my case at least it’s very straightforward to use:

        NativeLibraryLoader.registerNativeLibrary("jolt-jni",
                Platform.Linux64,
                "linux/x86-64/com/github/stephengold/libjoltjni.so");
        NativeLibraryLoader.registerNativeLibrary("jolt-jni",
                Platform.MacOSX64,
                "osx/x86-64/com/github/stephengold/libjoltjni.dylib");
        NativeLibraryLoader.registerNativeLibrary("jolt-jni",
                Platform.MacOSX_ARM64,
                "osx/aarch64/com/github/stephengold/libjoltjni.dylib");
        NativeLibraryLoader.registerNativeLibrary("jolt-jni",
                Platform.Windows64,
                "windows/x86-64/com/github/stephengold/joltjni.dll");

        NativeLibraryLoader.loadNativeLibrary("jolt-jni", true);

I haven’t looked at building KK Physics for Android yet. I might re-evaluate when I get to that point.

The current design essentially decomposes the library job into its main constituents: Compressed Locator - Platform detection - File Locator - File Extractor - Buffered Byte Stream - Native Library Loading. So it typically adds abstractions for all these constituents

The design of jSnapLoader sounds very impressive. I see there’s an already alpha build up at Maven Central. What needs to occur before the library is ready for production?

1 Like

I guess not so very much work. The addition of other non-common platforms (e.g. Linux-ARM32, Linux-ARM64, …), testing on the Android platform, and evaluation for memory leaks (since the library uses input/Output streams and autoclosables). If you’re willing to use it, let me know and I will build a plan to scale it within weeks, and we could talk in a new thread, so we won’t disrupt this thread.

1 Like