Rotate Camera around target

This is my code:
public override void Update(GameTime gameTime)
{
//Get new cameraDirection from rotation matrix
cameraDirection = Vector3.TransformNormal(cameraDirection, Matrix.CreateFromAxisAngle(actor.world.Up, (-MathHelper.PiOver4 / 60) * (Mouse.GetState().X - prevMouseState.X)));
cameraPosition = target - cameraDirection;

        prevMouseState = Mouse.GetState();
        //Reset cameraDirection
        cameraDirection = target - cameraPosition;
        CreateLookAt();
        base.Update(gameTime);
    }

X-axis of cameraPosition works fine, but Z-axis keeps decreasing which makes camera keeps approaching the target. Even if I try to rotate camera back, the camera is still approaching the target. I tired to search some solution but only get similar code as mine.

Update: cameraDirection.Normalize() does not work, so I do not use cameraDirection*distance to get cameraPosition. How to use Normalize()?

Here’s my Camera class, might be worth taking a look at to see how what you’re doing differs. OrbitAround(Vector3 orbitPt, float x, float y) is where you’d start looking.

If I were doing it over again I’d just setup a quaternion and rotate the position-orbitPt for the new position and recalculate the direction from that rather than the yaw and pitch nonsense.

Update: cameraDirection.Normalize() does not work, so I do not use cameraDirection*distance to get cameraPosition. How to use Normalize()?

It works, you’re probably using Matrix.CreateLookAt incorrectly. It looks at a target point, not along a vector, so it has to be cameraPos + cameraDirection for the cameraTarget.

The matrix and quaternion calculations produce precision errors over time, these are typically rounding down errors so it will wind your position down.

You need to get the distance at the time you order the rotation. Like when you issue the order be it programatically or keypress. You save that distance ( Only ) at that time and keep reusing it later.

// class level declaration
float desiredOrbitalDistance = 1f;

then in the method

if(IsOrbitOrdeBeingIssued)
{
desiredOrbitalDistance = Vecor3.Distance(target - cameraPosition);
}

then as you rotate and you find the new direction as you do.

cameraDirection = Vector3.TransformNormal(cameraDirection, 
Matrix.CreateFromAxisAngle(actor.world.Up, (-MathHelper.PiOver4 / 60) * 
(Mouse.GetState().X - prevMouseState.X)));

You then normalize the result, in order to multiply the normalized unit length direction vector by the distance.

cameraDirection.Normalize();
cameraPosition = cameraDirection * desiredOrbitalDistance;

then use your create look at

position_ = orbitPt - direction_ * (orbitPt - position_).Length();
I assume this part equals to: cameraPosition = target - cameraDirection*distance, but cameraPosition.Z is still decreasing no matter which direction I rotate.

Then I do this:

int ang = Mouse.GetState().X - prevMouseState.X;
currentCameraDirection = Vector3.TransformNormal
(cameraDirection, Matrix.CreateFromAxisAngle(actor.world.Up, (-MathHelper.PiOver4 / 900) * ang));

Vector3 result_ = currentCameraDirection - cameraDirection;

result_.X = MathHelper.Clamp(result_.X, -1f, 1f);
result_.Z = MathHelper.Clamp(result_.Z, -1f, 1f);

position = position - result_ * distance;

I get vector of currentCameraDirection - previous cameraDirection, then use position to minus this vector*distance, so I can get the new position, and create view matrix based on the new position. The problem of Z-axis still exist…

See my answer you basically have it already your just missing a logical step.

I have tried to get new distance. Although the distance works fine now, the camera keeps flashing back and forward.
The following is part of position output:

Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):22.21576 0 97.50108
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):-22.34338 0 -97.47192
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):22.34338 0 97.47192
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):-22.47095 0 -97.44259
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):22.47095 0 97.44259
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):-22.85363 0 -97.35355
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):23.23595 0 97.263
Mono_ThirdPerson.Camera.Update(Microsoft.Xna.Framework.GameTime):-24.00069 0 -97.07713

seems cameraPosition keeps inverting and causes the flashing.

Thats probably your mouse code. Get the basics working first then do what you want with the mouse.

float rotationAngle = 0f;

public SomeMethod{

rotationAngle += .01f;

if(rotationAngle > pi2 ) 
 rotationAngle = 0.0f;

cameraDirection = Vector3.TransformNormal(cameraDirection, 
Matrix.CreateFromAxisAngle(actor.world.Up, rotationAngle );

This is my code:

public override void Update(GameTime gameTime)
{
int ang = Mouse.GetState().X - prevMouseState.X;
float distance_ = Vector3.Distance(target,position); //new distance_
cameraDirection = Vector3.TransformNormal
(cameraDirection, Matrix.CreateFromAxisAngle(actor.world.Up, (-MathHelper.PiOver4 / 60) * ang));
cameraDirection = Vector3.Normalize(cameraDirection);
position = cameraDirection * distance_;

        prevMouseState = Mouse.GetState();
        cameraDirection = target - position;
        CreateLookAt();
        base.Update(gameTime);
    }

oh this line is wrong sorry i didn’t catch that.

Matrix m = Matrix.CreateFromAxisAngle(actor.world.Up, rotationAngle);

I think it is not a mouse code problem, since the problem still there after I removing mouse code:

float ang = 0f;

public override void Update(GameTime gameTime)
{
//float ang = Mouse.GetState().X - prevMouseState.X;
ang += 0.01f;
if(ang > MathHelper.TwoPi)
{
ang = 0f;
}
float distance_ = Vector3.Distance(target,position);
cameraDirection = Vector3.TransformNormal
(cameraDirection, Matrix.CreateFromAxisAngle(actor.world.Up, (-MathHelper.PiOver4 / 60) * ang));
cameraDirection = Vector3.Normalize(cameraDirection);
position = cameraDirection * distance_;

        cameraDirection = target - position;
        CreateLookAt();
        base.Update(gameTime);
    }

now it automatically rotate without any mouse input, but the model is still flashing

well here i wrote this out really quick so you can get the gist of it as i don’t really have time to make a full example.

        // c camera position t target position p transformed position of the camera
        // dist is the distance to maintain from the target
        // rotation in this case ranges from 0 to 1f
        float rotation = .9f;
        Vector3 c = new Vector3(2.0f, 0f, 0f);
        Vector3 t = new Vector3(7.0f, 0f, 0f);
        Vector3 t_forward = new Vector3(0.0f, 1f, 0f);
        //float dist = Vector3.Distance(t, c);
        float dist = 12f;
        Matrix m = Matrix.CreateFromAxisAngle(t_forward, (float)(Math.PI * 2f) * rotation);
        Vector3 p = Vector3.Normalize(c - t) * dist;
        p = Vector3.Transform(p, m);

        Console.WriteLine("dist: " + dist + " c: " + c + " p will be the new c distance is stored  p: " + p);
        // output
        //dist: 12 c: { X: 2 Y: 0 Z: 0}
        //p will be the new c, distance is stored, p: { X: -9.708203 Y: 0 Z: -7.053424}

If you want you can watch this code (Python) to rotate a camera. It’s not that hard :stuck_out_tongue:
https://www.panda3d.org/manual/index.php/Controlling_the_Camerahttps://www.panda3d.org/manual/index.php/Controlling_the_Camera

Thanks for your help. Your code and my test code of a single rotation output the correct position, while the position outputs are not correct once I update and rotate the camera. That is the what I am confused with. What I did is simply add 0.01 to angle every tick, but get a wired result.

I assume it is not a mouse nor math problem, so I will try to write my own update method instead of overriding Update() method.