BetterCharacterControl jittering

Hello,
when using a simple BetterCharacterControl and a static RigidBody, it seems that there is quite a lot of jittering in physics. This video demonstrates the issue:

I could try to provide a minimal working example, but maybe you can spot a bug in my code:

From the PhysicsAppState:

public void addPlayer(Spatial mage) {
        BetterCharacterControl bcc = new BetterCharacterControl(.5f, 1.8f, 72);
        bcc.warp(new Vector3f(0, 2, 0));
        mage.addControl(bcc);
        bas.getPhysicsSpace().add(bcc);
    }

This is the method to apply the inputs:

PhysicsAppState pas = app.getStateManager().getState(PhysicsAppState.class);
        Spatial mage = app.getStateManager().getState(HandsState.class).getMage();
        Vector3f walkDirection = new Vector3f(0, 0, 0);
        if (booleans.isW()) {
            walkDirection.addLocal(app.getCamera().getDirection().clone().mult(3));
        }
        if (booleans.isA()) {
            walkDirection.addLocal(app.getCamera().getLeft().clone().mult(1.5f));
        }
        if (booleans.isS()) {
            walkDirection.addLocal(app.getCamera().getDirection().clone().negate());
        }
        if (booleans.isD()) {
            walkDirection.addLocal(app.getCamera().getLeft().clone().negate().mult(1.5f));
        }
        walkDirection.setY(0);
        // System.out.println(walkDirection);
        pas.setWalkDirection(mage, walkDirection);

And the HandsState:

public class HandsState extends AbstractAppState {

    private float time = 0;
    private Spatial mage;
    private AnimationControl animationControl;

    @Override
    public void initialize(AppStateManager stateManager, Application application) {
        super.initialize(stateManager, application);
        initHands();
    }

    private void initHands() {
        mage = app.getAssetManager().loadModel("Models/mage/mage.j3o");
        mage.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
        mage.setCullHint(Spatial.CullHint.Never);
        app.getRootNode().attachChild(mage);

        animationControl = new AnimationControl();
        mage.addControl(animationControl);
        animationControl.setAnim("Idle", .05f, LoopMode.Loop);
    }

    @Override
    public void update(float tpf) {
        time += tpf;
        app.getCamera().setLocation(mage.getWorldTranslation().add(0, 1.5f, 0));
        System.out.println(mage.getWorldTranslation());
    }

    @Override
    public void render(RenderManager rm) {
    }

    public Spatial getMage() {
        return mage;
    }
}

Even when standing still there is noticable jitter (as you can hopefully see in the video) and the translation of the model actually changes a tiny bit:

(0.0, -6.8243E-8, 0.0)
(0.0, -5.334529E-8, 0.0)
(0.0, -4.599129E-8, 0.0)
(0.0, -4.599129E-8, 0.0)
(0.0, -3.8447574E-8, 0.0)
(0.0, -3.1093574E-8, 0.0)
(0.0, -2.354986E-8, 0.0)
(0.0, -0.0027250163, 0.0)
(0.0, -0.0021800196, 0.0)
(0.0, -0.0017440161, 0.0)
(0.0, -0.0013952141, 0.0)
(0.0, -0.0011161735, 0.0)
(0.0, -8.9294655E-4, 0.0)

I’m not sure if that is the cause though… But what can I do?

No idea about the jitter, I’ve also got it but it does not bother me in my context.

If you are placing the camera at the position of the character control, I guess you could keep a fixed Y value, then only change the cameras Y if the control changes by an amount over a certain fresh-hold? Might be a pain for stairs and what not.

I don’t know why and how this jittering is happening but if you really want to use physics, maybe you could use the position you get from physics as a target position and not as THE position.
You’ll have the “current” object’s position and the target “physics” position. You then move your current position in the direction of the physics position following a simple math function. That will smoothen the jitter so that I won’t be perceivable.
That may be as simple as : nextPosition = oldPosition + (tps * speed * direction_towards_physics_position).
Speed could be the squared distance between oldPosition and physics_position

Thanks for all the ideas but I just managed to fix it. I simply created an empty Node and attached the BetterCharacterControl to it. I then set the walkDirection for that empty Node and update the position of the camera and spatial every frame with the localTranslation of the empty Node. I don’t know exactly why this works as the y value of the localTranslation of that empty node still isn’t constant… But at least it works :slight_smile:
Maybe it is because Bullet applies some more forces to physics-controlled spatials or so? But then I would see it too if I update the translation…

Long time ago, when I made the KinematicRagDollControl, I had this kind of issue with physics.
I used a low pass filtering on the position (similar to what @guillaumevds is suggesting).
Basically that’s ignoring very small variations of the physic position ( if positionDelta < epsilon forget about it)

1 Like