Question

Lately I've succeed in implementing first person camera and terrain collision but I've hit yet another wall which is camera jittering when moving across the height-map. While it's not so uncommon problem I couldn't find any clear solution nor direction I should follow to achieve desired effect. Can anyone suggest how could I adapt my implementation to make rendering perform smooth?

Camera class:

public class Camera
{
    public Matrix view { get; protected set; }
    public Matrix projection { get; protected set; }
    public Vector3 direction { get; protected set; }
    public Vector3 side_direction { get; protected set; }
    public Vector3 position { get; set; }
    public Vector3 up { get; protected set; }
    public float _rotationX { get; protected set; }
    public float _rotationY { get; protected set; }
    public float rotX
    {
        get { return _rotationX; }
        set
        {
            _rotationX = value;
            RotateX(value);
        }
    }
    public float rotY
    {
        get { return _rotationY; }
        set
        {
            _rotationY = value;
            RotateY(value);
        }
    }
    public Matrix rotationX;
    public Matrix rotationY;
    public Camera(Game game, Vector3 pos, Vector3 up)
        : base(game)
    {
        this.direction = new Vector3(0, 0, 1);
        this.side_direction = new Vector3(1, 0, 1);
        this.rotationX = Matrix.Identity;
        this.rotationY = Matrix.Identity;
        this.position = pos;
        this.up = up;
        this.view = Matrix.CreateLookAt(pos, pos + direction, up);
        this.projection = Matrix.CreatePerspectiveFieldOfView(
                     MathHelper.PiOver4, (float)Game.Window.ClientBounds.Width /
                     (float)Game.Window.ClientBounds.Height,
                     1, 3000);
    }
    public override void Initialize()
    {
        base.Initialize();
    }
    public void RotateX (float degree)
    {
        if (_rotationX + degree >= 89)
            _rotationX = 89;
        else if (_rotationX + degree <= -89)
            _rotationX = -89;
        else
            _rotationX = _rotationX + degree;
        float radians = MathHelper.ToRadians(_rotationX);
        rotationX = Matrix.CreateRotationX(radians);
        updateView();
    }
    public void RotateY (float degree)
    {
        _rotationY = (_rotationY + degree) % 360;
        float radians = MathHelper.ToRadians(_rotationY);
        rotationY = Matrix.CreateRotationY(radians);
        updateView();
    }
    protected void updateView()
    {
        this.side_direction = Vector3.Transform(new Vector3(1, 0, 1), rotationX);
        this.direction = Vector3.Transform(new Vector3(0, 0, 1), rotationX);
        this.side_direction = Vector3.Transform(side_direction, rotationY);
        this.direction = Vector3.Transform(direction, rotationY);
        this.view = Matrix.CreateLookAt(position, position + direction, up);
    }
    public override void Update(GameTime gameTime)
    {
        base.Update(gameTime);
    }
    public void moveForward(float p)
    {
        this.position = position + direction * p;
        updateView();
    }
    public void moveSide(float p)
    {
        this.position = position + side_direction * p;
        updateView();
    }
    public void moveForward(float p, Terrain t)
    {
        Vector3 tmp = position + direction * p;
        tmp.Y = t.GetTerrainHeight(tmp.X, tmp.Z);
        this.position = tmp;
        updateView();
    }
    public void moveSide(float p, Terrain t)
    {
        Vector3 tmp = position + side_direction * p;
        tmp.Y = t.GetTerrainHeight(tmp.X, tmp.Z);
        this.position = tmp; 
        updateView();
    }
    public void Draw(ref BasicEffect effect)
    {
        effect.Projection = this.projection;
        effect.View = this.view;
    }
}

`

Was it helpful?

Solution

Could you say us more about GetTerrainHeight function? As far as I can read, you are reading terrain height directly - is it stored in an array or something?
Try to interpolate terrain height between adjacent points as your character position can easily be between two or more data points (if I understood your code right).

UPD:
Try to lerp between current camera position and calculated camera position instead of immediately assigning it:
this.position = Vector3.Lerp(this.position, tmp, 0.05f);
0.05f is the threshold by what percent (in range from 0.0f to 1.0f) you want to move towards target. Calibrate it or even introduce GameTime to make smoothing independent from your framerate.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top