About the lag caused by using minie

I use this code to generate the grid

package scenario.Grid;

import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Quad;
import com.jme3.util.BufferUtils;
import static scenario.scenarioState.mapGrid3D;

/**
 *使用Mesh生成网格
 * @author IcyBoxs
 */
public class meshGrid {

   public Geometry GameMap(float XLength,float YHighly,float ZWidth,float cellsize) {
        int Length = (int)XLength/(int)cellsize;
        int Highly = (int)YHighly/(int)cellsize;
        int Width = (int)ZWidth/(int)cellsize;
        
        float spacing = cellsize;
//     float XLength=XLength;//长度X
//     float XHighly;//高度Y
//     float ZWidth;//宽度Z
//    
//     float cellsize;//单元格长度
        // Define vertices for the grid 
        //定义网格顶点
        float[] vertices = new float[Length * Width * 3];
        for (int x = 0; x < Length; x++) {
            for (int z = 0; z < Width; z++) {
                vertices[(x * Width + z) * 3] = x * spacing;
            
                vertices[(x * Width + z) * 3 + 1] = YHighly;
    
                
                vertices[(x * Width + z) * 3 + 2] = z * spacing;
            }
        }

        // Define indices to create triangles
        int[] indices = new int[(Length - 1) * (Width - 1) * 6];
        int idx = 0;
        for (int x = 0; x < Length - 1; x++) {
            for (int z = 0; z < Width - 1; z++) {
                int topLeft = x * Width + z;
                int topRight = topLeft + 1;
                int bottomLeft = (x + 1) * Width + z;
                int bottomRight = bottomLeft + 1;

                // First triangle 第一个三角形
                indices[idx++] = topLeft;
                indices[idx++] = bottomLeft;
                indices[idx++] = topRight;

                // Second triangle 第二个三角形
                indices[idx++] = topRight;
                indices[idx++] = bottomLeft;
                indices[idx++] = bottomRight;
            }
        }
        // Create a Mesh
        Mesh mesh = new Mesh();
        mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
        mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer(indices));
        mesh.updateBound();

        // Create a Geometry to display the mesh
        Geometry gridGeometry = new Geometry("Grid", mesh);
       
        return gridGeometry;
    }
}

At first my intention was just to put this mesh into the physical world in order to simulate parts of the map (like the floor we step on)

        CollisionShape sceneShape = CollisionShapeFactory.createMeshShape(gridGeometry);
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        map.addControl(landscape);

Like this I converted it into a rigid body.

And I have a lot of tanks. I put tanks in collisions.

BoxCollisionShape capsuleShape = new BoxCollisionShape(radius, height, radius);
        player = new CharacterControl(capsuleShape,stepHeight);
        player.setPhysicsLocation(new Vector3f(0, 10f, 0));
        MinieBulletAppState.bulletAppState.getPhysicsSpace().add(player);

At this point the question arises!

The graphics card becomes very laggy when the tank’s collision body touches a rigid body.

I don’t really understand what’s happening to cause the graphics card to lag so much, but I did a test and it doesn’t happen if I use an oversized mesh made from blender as a rigid body.
If I use the Geometry generated by the mesh code above as a rigid body I get severe lag on the graphics card.
If anyone knows what’s going on please let me know thank you very much!

//If you have any doubts about my questions, please point them out.

This is a test code just copy this code into your ide and run it!

package com.mygame;

import com.jme3.app.DetailedProfilerState;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.collision.shapes.BoxCollisionShape;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.control.CharacterControl;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.bullet.util.CollisionShapeFactory;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.Mesh;
import com.jme3.scene.Node;
import com.jme3.scene.VertexBuffer;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.util.BufferUtils;

/**
 *
 * @author icyboxs
 */
public class SimpleTestGridApp extends SimpleApplication {
    public static BulletAppState bulletAppState;
    private CharacterControl player;
    private Node block = new Node("block");
    public static void main(String[] args) {
        SimpleTestGridApp app = new SimpleTestGridApp();
        AppSettings setting = new AppSettings(true);
        setting.setWindowSize(1920, 1080);   
        app.setSettings(setting);
        app.start();
    }
    @Override
    public void simpleInitApp() {
        DetailedProfilerState detailedProfilerState = new DetailedProfilerState();
        getStateManager().attach(detailedProfilerState);
        bulletAppState = new BulletAppState();
        bulletAppState.setThreadingType(BulletAppState.ThreadingType.PARALLEL);
        getStateManager().attach(bulletAppState);//添加物理世界
        bulletAppState.setDebugEnabled(true);
        

        Geometry gridGeometry = GameMap(1280, 0, 1280, 5);
        Material material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        material.setColor("Color", ColorRGBA.Red);
        material.getAdditionalRenderState().setWireframe(true);
        material.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);
        gridGeometry.setMaterial(material);
        for(int i=1;i<=20;i++){
            for(int j=1;j<=20;j++){
            addT100(new Vector3f(30*j,300,30*i));
            }
        
        }
        
 
        
        
        CollisionShape sceneShape = CollisionShapeFactory.createMeshShape(gridGeometry.clone());
        RigidBodyControl landscape = new RigidBodyControl(sceneShape, 0);
        gridGeometry.addControl(landscape);
        bulletAppState.getPhysicsSpace().add(landscape);
        bulletAppState.startPhysics();
   rootNode.attachChild(gridGeometry);



        // #4 创建一束定向光,并让它斜向下照射,好使我们能够看清那个方块。
        DirectionalLight sun = new DirectionalLight();
        sun.setDirection(new Vector3f(-1, -2, -3));
        
        // #5 将方块和光源都添加到场景图中
        rootNode.attachChild(block);
        rootNode.addLight(sun);
    }
    
    
    public void addT100( Vector3f v3f){
 	// #1 创建一个方块形状的网格
        Mesh box = new Box(2f, 2f, 2f);

        // #2 加载一个感光材质
        Material mat = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");

        // #3 创建一个几何体,应用刚才和网格和材质。
        Geometry geom = new Geometry("Box");
        geom.setMesh(box);
        geom.setMaterial(mat);
        geom.setLocalTranslation(v3f);
        float radius = 5.5f;// 胶囊半径0.3米
        float height = 5.5f;// 胶囊身高1.8米
        float stepHeight = 0.5f;// 角色步高0.5米  
        BoxCollisionShape capsuleShape = new BoxCollisionShape(radius, height, radius);
        player = new CharacterControl(capsuleShape,stepHeight);
        player.setJumpSpeed(10f);// 起跳速度
        player.setFallSpeed(20f);// 坠落速度
        player.setGravity(9.81f * 3);// 重力加速度
        player.setPhysicsLocation(v3f);
        bulletAppState.getPhysicsSpace().add(player);
        geom.addControl(player);
        block.attachChild(geom);
    }
    
    
    public Geometry GameMap(float XLength,float YHighly,float ZWidth,float cellsize) {
        int Length = (int)XLength/(int)cellsize;
        int Highly = (int)YHighly/(int)cellsize;
        int Width = (int)ZWidth/(int)cellsize;
        
        float spacing = cellsize;
//     float XLength=XLength;//长度X
//     float XHighly;//高度Y
//     float ZWidth;//宽度Z
//    
//     float cellsize;//单元格长度
        // Define vertices for the grid 
        //定义网格顶点
        float[] vertices = new float[Length * Width * 3];
        for (int x = 0; x < Length; x++) {
            for (int z = 0; z < Width; z++) {
                vertices[(x * Width + z) * 3] = x * spacing;
            
                vertices[(x * Width + z) * 3 + 1] = YHighly;
    
                
                vertices[(x * Width + z) * 3 + 2] = z * spacing;
            }
        }

        // Define indices to create triangles
        int[] indices = new int[(Length - 1) * (Width - 1) * 6];
        int idx = 0;
        for (int x = 0; x < Length - 1; x++) {
            for (int z = 0; z < Width - 1; z++) {
                int topLeft = x * Width + z;
                int topRight = topLeft + 1;
                int bottomLeft = (x + 1) * Width + z;
                int bottomRight = bottomLeft + 1;

                // First triangle 第一个三角形
                indices[idx++] = topLeft;
                indices[idx++] = bottomLeft;
                indices[idx++] = topRight;

                // Second triangle 第二个三角形
                indices[idx++] = topRight;
                indices[idx++] = bottomLeft;
                indices[idx++] = bottomRight;
            }
        }
        // Create a Mesh
        Mesh mesh = new Mesh();
        mesh.setBuffer(VertexBuffer.Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
        mesh.setBuffer(VertexBuffer.Type.Index, 3, BufferUtils.createIntBuffer(indices));
        mesh.updateBound();

        // Create a Geometry to display the mesh
        Geometry gridGeometry = new Geometry("Grid", mesh);
       
        return gridGeometry;
    }
    
}

1 Like

I don’t understand what’s causing this to happen with the GPU, but there are a few of things that stand out to me:

  1. What’s the resolution of your grid? You’re generating a mesh collision shape for it, but in this example it’s a flat plain. Assuming you’re working towards a hilly map, you don’t want a mesh collider for terrain, you want a heightfield collision shape - they’re much more efficient.

  2. Why is this all in the GUI bucket? It looks like all of your objects have been added there. If that’s what you intended then it’s fine, but it’s a bit odd to me that it would be the case.

  3. Your tank collision code is giving all tanks the same physics location, meaning that they’re all overlapping. This is the worst case for the physics engine since for each tank it has to simulate it colliding with all other tanks. This could be the source of your problem if you have enough tanks, though if it is I’m surprised that it would show up under the GPU measurement.

1 Like

That’s what puzzles me so much I’m still troubleshooting. :smiling_face_with_tear:

One thing that might narrow it down a bit is if you set the physics location of each tank to the visual location - you’ve got them nicely spaced out on the grid visually, but the code you showed will simulate their physics as if they’re all in the same place. If that clears your performance problem, at least that’s one problem gone.

Each tank is in a separate node, each collider is in a separate node they won’t be in the same position sorry I didn’t show it fully in my code


This image shows you that each collision body is a box, and they’re distributed among the nodes of the tanks.

I’m working on a separate example and if the same thing still happens I’ll post the code, if it doesn’t then that means there’s probably a problem somewhere in my pile of code

1 Like

Ok, so to make sure I understand - this screenshot here shows the tanks as soon as the application starts, and the former image (with the high frame time) shows them as soon as they make contact with the grid?

Here’s the thing I was trying to determine what was wrong, I first tried just the tank then I tried just the mesh and found no problems then I put the tank in free fall in a higher position and then I found that only when the collision body touches the rigid body it becomes very laggy.
Then I made a similar mesh from blender and saved it as a gltf file and then used it in jme to convert the mesh into a rigid body and found that the problem disappeared. At this point I figured out that I had a mesh problem.
But I can’t really understand what’s causing it I’m currently troubleshooting it one by one as well

What’s the difference between the “oversized mesh” you made in Blender and the geometry? If the geometry that triggers your problem is the grid mesh, then switching from a mesh collision shape to a heightfield collider will likely fix it, or at least greatly improve the situation. Mesh collision shapes are kind of the worst of all worlds, and should be avoided if it’s possible to use something else instead.

1 Like

I’ve added a test case where this issue still exists, you can run this test code to help troubleshoot the issue

It looks like you’re trying to use 400 charactrer controls, so i wonder if that is just too many? Even if they arent overlapping each other, thats still 400 constant physics interactions happening against the terrain or whatever is underneath.

I know that BetterCharacterControl gave me framerate issues at 20-30 added to a small scene, so i wouldnt be surprised if the regular CharacterControl has simiar performance issues at high counts.

1 Like

My problem was solved but I don’t really know why it was solved.
I enlarged the grid.

Geometry gridGeometry = GameMap(1280, 0, 1280, 5);

I adjusted the length of each grid from 5 to 20 I noticed that the lag on the graphics card disappeared!
Then I made a mesh from blender and adjusted the mesh length to 5 and found that it also lags.

I don’t know exactly what happened here.

Maybe our physics expert @sgold can explain it.

//This is of course if you are interested, have the time, and are willing to

So far my problem’s been solved, and I’m embarrassed that I don’t know what’s going on. :sweat_smile:

Physics performance gets complicated, and you haven’t explained what you did in enough detail for me to guess what happened.

In general, the key to good physics performance is:

  1. minimize the number of physics objects (such as bodies, characters, and vehicles)
  2. simplify the collision shapes of those objects (capsule not gimpact, heightfield not mesh, box not compound)

For large numbers of physics objects, the CPU time spent on physics grows at a quadratic rate, roughly as the square of the number of objects (N^2).

The first corollary is that all the non-moving objects (terrain, buildings, walls, signposts) should be merged into a single physics object.

If your game has 400 dynamic physics objects, that’s over-ambitious, unless they’re all boxes or spheres.

If you want to pursue this further, tell me how many physics objects there are and what their collision shapes are. An easy way to get this information would be to “dump” the physics space using

    new PhysicsDumper().dump(physicsSpace);

For more information on using PhysicsDumper see Troubleshooting physics issues :: The Minie project

4 Likes

There seems to be a bit too much content to present directly in the forums。
I’d like to use minie’s ragdoll system to simulate the effects of unit deaths, e.g. when a tank unit dies it makes the tank fall apart into pieces

1 Like

The tank is not a bone/skeleton animated object, surely. Is it? (If so then that’s very strange.)

…would be perhaps better (on death) to just replace the whole tank with a bunch of separate parts and let them fall apart as they will.

2 Likes

I see from the physics dump that there are 1600 characters in the physics space. I assume all 1600 represent tanks. The ones I looked at (the first few) all have box shapes. I don’t know what hardware you’re running on, but I suspect this might be pushing the limits of your CPU.

If you really need to simulate the destruction of 1600 tanks, there are shortcuts you should consider. The first idea that comes to my mind would be to simulate in detail the destruction of a single tank, recording the position of each fragment after each physics step and storing that information in an animation clip. During play, destruction of a tank would be visualized by playing the animation.

1 Like

That’s a good idea I’ll give it a go

1 Like

I have looked up some information and it’s really as you say, I’ve tried to look for some other ways to do it, thanks for your reply!

1 Like

In your case, the tank is a very complex shape, and the grid is also a complex shape, so the collision detection is taking up a lot of processing power.

There are a few things you can do to try to improve the performance of your game:

  • Reduce the complexity of the tank and grid meshes.
  • Use a simpler collision shape for the tank.
  • Use a different physics engine.

If you have tried all of these things and your game is still lagging, you may need to upgrade your graphics card. A more powerful graphics card will be able to handle the collision detection more efficiently

Note: the above is likely an AI generated post because it is internally self-contradictory and in at least one case seems to pull random technology out of thin air (in the context of this discussion.)

It was up for review for being posted too quickly and I was on the fence about discarding it… apparently someone else was not on the fence. It is a weird place we find ourselves in.

If the person is a real life human being then I look forward to the indignant response.

Else, best ignored as (at best) providing no significant value.

1 Like

updated