I Compared Jmonkeyengine 3.6 with Godot 4.2

You have a powerful machine than I have. Thanks by the way for motivating me. your test is also very nice and it is very helpful to me.

1 Like

almost 1000 Cubes with 50 to 60 FPS. Dropped to 13 FPS at 1060 boxes. Thanks for this test. Thanks for providing Windows Executeables.

1 Like

Can you provide Windows executables ? if possible !

1 Like

As a final experiment, I switched the textures back on, to see how much difference it would make. To my surprise, on my machine there’s hardly any; but this is probably because the texture processing is being offloaded onto the GPU. However, I ran both tests again using watch -d -n 0.5 nvidia-smi to monitor GPU load and the difference between the two runs was small: with textures was 18% ± 2%; without was 17% ± 2%.

1 Like

I have absolutely no idea how to make a Windows executable, nor could I test one if I did!

Could somebody give me some pointers?

1 Like

Out of interest, I’ve rerun my (untextured) test with vsync off. Initial framerate was over 3,000, but it dropped steadily. However, it didn’t fall below 60 until after 2,500 blocks, so actually very slightly better performance than with vsync on.

1 Like

yes, in Godot you have Jolt physics plugin. Its a lot of difference.

Its much different than Bullet ones. and muuch faster. (not made for simulation tho, just for game industry)

Bullet one comparison i would not see so much difference.

2 Likes

I also don’t know. by the way. thanks for your time.

Thank you v. much guys. One of you provided Windows & Linux Executables. I tested it and I got almost 3X more cubes at 60 FPS.
This is not a small community. I’m amazed how fast you guys have helped in in just one week. less than one week I would say. Thank you JME community.

2 Likes

Yes sure, I make use of packr lib. You can see instructions here:

4 Likes

Thanks, working on it!

2 Likes

when done. upload files. I will test.

Test 2 link: https://youtu.be/Am35T_sk3vM

Thanks for posting the Test 2 video. It looks like graphics does not have much effect on the performance of your test.

I’d like to understand why Jolt Physics is faster. Has anyone determined the reasons? Does it use better algorithms, and if so, which ones? Does it provide the same simulation quality?

I asked whether the source code for each test was available, which library was used, and what time step was used. I’m still curious. In the absence of source code, I wonder what settings your app uses that might affect performance.

One concern I have is that Bullet with defaults settings will perform up to 4 simulation steps per frame. And it does so consistently under heavy load, trying to achieve real-time simulation with good accuracy. I suspect a lot of devs are unaware of this feature, and I assume other physics engines don’t do this. So when people compare Bullet with other physics engines under heavy load, Bullet is simulating 4x as many steps!

Since your test doesn’t care about real-time simulation or accuracy, you can configure your app (during initialization) to simulate only one step per frame:

physicsSpace.setMaxSubSteps(1);

I’d be curious to know how that change affects the behavior of your test, if at all.

This presentation, by the designer of Jolt, gives a good explanation.

Note particularly that he isolates the phases which need to be done in a single thread, which implies (although I’m not sure he says explicitly) that he’s multi-threading as much as he can – which makes a lot of sense on modern multi-core processors.

2 Likes

(yes, he does talk about multi-threading – from about 12:30 in).

This test looked implausible to me

I too, created my own test, but written in Java. Like the OP’s test, it creates a fountain of endless boxes. My version terminates automatically when FPS falls below 30. The final box count seems to be reproducible within about +/- 3%.

I ran some tests on my 2021-vintage gaming laptop. With a little tuning, I achieved 2790-2831 boxes at 30 FPS:

  • Linux Mint 21.3 edge (6.5.0-35 kernel)
  • OpenJDK 64-Bit Server VM Temurin-17.0.10+7
  • assertions disabled
  • JMonkeyEngine v3.6.1-stable
  • LWJGL v3.3.2
  • 640x480 window, VSync on
  • Minie v8.1.0 physics library
  • setMaxSubSteps(1)
  • BroadphaseType.AXIS_SWEEP_3

I report the measured range of boxes at 30 FPS (2790 to 2831) over 3 separate runs. 2800 boxes seems to me like a plausible baseline for physics performance (though of course I wish it were higher).

Using setMaxSubSteps(4) (the default setting) limits the number of boxes to 1714-1800, about a 37% reduction.

Using BroadphaseType.DBVT limits the number of boxes to 2568-2634, about a 7% reduction.

Using jme3-jbullet in place of Minie limits the number of boxes to 1397-1425, about a 45% reduction. (Tested with DBVT because AXIS_SWEEP_3 is broken in JBullet.)

Here is the source code:

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.PhysicsSpace;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.font.BitmapText;
import com.jme3.material.Material;
import com.jme3.material.Materials;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import java.util.logging.Level;
import java.util.logging.Logger;
import jme3utilities.Heart;

/**
 * The "fountain of boxes" stress test to estimate how many active dynamic rigid
 * bodies can be simulated while rendering 30 frames per second.
 *
 * @author Stephen Gold sgold@sonic.net
 */
public class Main extends SimpleApplication {

    private static BitmapText statusDisplay;
    private static Box smallBox;
    private static BoxCollisionShape smallBoxShape;
    private static float secondsSinceFpsUpdate = 0f;
    private static int framesSinceFpsUpdate = 0;
    private static int numBoxes = 1;
    private static Material solidGray;
    private static PhysicsSpace physicsSpace;

    public static void main(String[] args) {
        Main app = new Main();
        app.start();
    }

    @Override
    public void simpleInitApp() {
        if (Heart.areAssertionsEnabled()) {
            System.out.println("Warning: assertions are enabled.");
        }

        // Disable logging of rigid-body creation:
        Logger prbLogger
                = Logger.getLogger("com.jme3.bullet.objects.PhysicsRigidBody");
        prbLogger.setLevel(Level.SEVERE);

        // Pre-position the main camera and disable FlyByCamera:
        cam.setLocation(new Vector3f(0f, 110f, 210f));
        cam.setRotation(new Quaternion(0f, 0.9777315f, -0.20985f, 0.00143f));
        flyCam.setEnabled(false);

        // Attach a simple status display to the GUI node:
        statusDisplay = new BitmapText(loadGuiFont());
        statusDisplay.setLocalTranslation(0f, settings.getHeight(), 0f);
        guiNode.attachChild(statusDisplay);

        // Create a high-gravity PhysicsSpace:
        BulletAppState bulletAppState = new BulletAppState();
        bulletAppState.setBroadphaseType(
                PhysicsSpace.BroadphaseType.AXIS_SWEEP_3); // default = DBVT
        bulletAppState.setWorldMax(new Vector3f(100f, 50f, 100f));
        bulletAppState.setWorldMin(new Vector3f(-100f, -200f, -100f));
        stateManager.attach(bulletAppState);
        physicsSpace = bulletAppState.getPhysicsSpace();
        physicsSpace.setGravity(new Vector3f(0f, -99f, 0f));
        physicsSpace.setMaxSubSteps(1); // IMPORTANT! default = 4
        System.out.printf("maxSubSteps = %d, numSolvers = %d%n",
                physicsSpace.maxSubSteps(), physicsSpace.countSolvers());

        // Add a big blue box to serve as a platform:
        float size = 99f; // half extent in world units
        Box bigBox = new Box(size, size, size);
        BoxCollisionShape bigBoxShape
                = new BoxCollisionShape(new Vector3f(size, size, size));
        Material solidBlue = new Material(assetManager, Materials.UNSHADED);
        solidBlue.setColor("Color", ColorRGBA.Blue);

        RigidBodyControl staticRbc = new RigidBodyControl(bigBoxShape, 0f);
        staticRbc.setPhysicsSpace(physicsSpace);

        Geometry bbGeom = new Geometry("BigBox", bigBox);
        rootNode.attachChild(bbGeom);
        bbGeom.move(0f, -size, 0f);
        bbGeom.addControl(staticRbc);
        bbGeom.setMaterial(solidBlue);

        smallBox = new Box(1f, 1f, 1f);
        smallBoxShape = new BoxCollisionShape(new Vector3f(1f, 1f, 1f));

        solidGray = new Material(assetManager, Materials.UNSHADED);
        solidGray.setColor("Color", ColorRGBA.DarkGray);
    }

    @Override
    public void simpleUpdate(float tpf) {
        // Drop a small, gray, dynamic box from (0, 40, 0):
        RigidBodyControl dynamicRbc = new RigidBodyControl(smallBoxShape, 1f);
        dynamicRbc.setPhysicsSpace(physicsSpace);

        Geometry sbGeom = new Geometry("", smallBox);
        rootNode.attachChild(sbGeom);
        sbGeom.move(0f, 40f, 0f);
        sbGeom.addControl(dynamicRbc);
        sbGeom.setMaterial(solidGray);
        ++numBoxes;

        // Update the status:
        String statusText = "numBoxes = " + numBoxes;
        statusDisplay.setText(statusText);

        // Update the FPS statistics:
        secondsSinceFpsUpdate += tpf;
        ++framesSinceFpsUpdate;
        if (secondsSinceFpsUpdate >= 1f) {
            // Calculate frames per second over a 1-second interval:
            float fps = framesSinceFpsUpdate / secondsSinceFpsUpdate;
            if (fps < 30f) {
                // Terminate the application if FPS drops below 30:
                System.out.println(statusText);
                stop();
            }
            secondsSinceFpsUpdate = 0f;
            framesSinceFpsUpdate = 0;
        }
    }
}
11 Likes

It was an interesting test, so I did a test in my editor as well.

1 Like

Yes, the main reason is better collision-check tree managment as i know. It have recursive QuadTree as i remember and special optimizations for it.

Also it disable physics for CS faster in better way

And Also it can “glue” CS together of elements to optimize even further

It was designed for Horizon Zero Dawn game, and later published openly by author i assume.

Its not physics for simulation, but made just for game purpose. (so its not simulation accurate)

You can read it here also:

4 Likes

Thanks

Continuing on from this discussion, there’s Java bindings project wrapping Jolt

I’m wondering whether it would be interesting and good learning to try to build bridge code to allow jMonkeyEngine projects to be switched relatively easily to use Jolt. Obviously this depends a lot on how similar the Jolt API is to the Bullet API, which I haven’t yet investigated.

There don’t seem to be many comparisons of the two out there on the Web yet, which seems to me a little surprising.

What I get from these discussions generally is:

Jolt uses multi-processor architectures much better than Bullet

In the Thrive discussion, Jolt’s documentation seems to be considered good, whereas Bullet’s is considered harder to use.

Given that, these days, most of the machines people play games on are multi-core machines, Jolt’s better ability to exploit multiple cores definitely seems a win.

1 Like