How can I achieve this camera effect?

Hey guys,

I’m pretty new to Monogame and 3D programming in general, and need some help with a specific camera rotation effect I’m trying to achieve.

Essentially what I want to be able to do is have the camera rotate around a point, origin is fine for this example, but while rotating I want the camera to be looking straight ahead, it’s rather difficult to explain so I’ve created a poorly drawn graphic to help describe what I’m talking here which shows the camera at different points of the rotation and the direction the camera should be facing.

I think I need to somehow translate the target vector of the camera so it’s relative to the position of the camera but I’m having a hard time getting the math right, so just looking for a nudge in the right direction if possible!

Thanks :slight_smile:

Basically you need to define a origin point that your camera will rotate around.
cameraPositionOriginOfRotation
Now your camera’s position will orbit this point. So you will still need to move this point around in the world.
You will make some extra values that go thru steps to orbit that position around that point of rotational origin.
You will make a rotational matrix which will describe a rotation that will have a directional axis, the rotation will orbit circularly around that axis on a perpendicular plane that is orthagonal to that direction vector.
The orbital position itself will be defined by 360 degrees of rotation, on that plane, around the directional vector you designate.
You will simply define a direction the camera is to look towards.
You will normalize that (well it depends).
You will either use it directly in create world () or create look at ()
Or you will add the current cameras position to that calculated normal in create world() or create look at().

Edit added a distance from origin vector to rotate by forgot that.

E.G,

// These variables control the orbital camera.
Vector3 cameraPositionOriginOfRotation = new Vector3(125, 43, 200f);
Vector3 cameraTarget = new Vector3(0, 0, -10000f); // a world position the camera will look towards
Vector3 cameraDistanceFromOrigin = new Vector3(0,0, 50); // the 50 is actually a distance.
Vector3 cameraOriginAxisVector = Vector3.Up; // if you make your own direction normalize it.

float cameraOrbitInDegrees = 15f; // now you loop this from 0 to 360 to orbit

float ToRadians = (float)(Math.PI *2d / 360f); // 1 360th rads 
float rotationInRadians = cameraOrbitInDegrees * ToRadians; // degrees to radians

// rotate the camera around some positional axis could be almost any vector3 that has been normalized() 
// typically you pick a axis by Vector3.Normalize(cameraTarget - cameraPosition);
Matrix m = Matrix.CreateFromAxisAngle(cameraOriginAxisVector, rotationInRadians);
Vector3 newCameraPosition = Vector3.Transform(cameraDistanceFromOrigin, m);
newCameraPosition += cameraPositionOriginOfRotation;

// typically you want a target for the view matrix. 
Matrix cameraWorldMatrix = Matrix.CreateWorld(newCameraPosition, Vector3.Normalize(cameraTarget - newCameraPosition), Vector3.Up);
Matrix cameraViewMatrix = Matrix.CreateLookAt(newCameraPosition, cameraTarget + newCameraPosition, Vector3.Up);

// However to do as you describe just send in the target as a straight up normalize direction.
Vector3 cameraFaceForward = new Vector3(0f, 0f, -1000); // this is not a target its a cameraLookAtDirection
Matrix cameraWorldMatrix_PerTheQuestion = Matrix.CreateWorld(newCameraPosition, Vector3.Normalize(cameraFaceForward) , Vector3.Up);
Matrix cameraViewMatrix_PerTheQuestion = Matrix.CreateLookAt(newCameraPosition, cameraFaceForward + newCameraPosition, Vector3.Up);

Those are the basic steps.
The code also offers a slight alternative to doing it as you described by setting a target that is not locked to a specific direction but could instead be a far off position as some look at target position in the distance.

This is not tested code i just wrote it straight out (though i wrote it to work).

Here is the matrix class create look at and create world are within.
So you can see what is initially done with the variables you pass.
The functions do normalize the forward and the (position - target) you pass so be aware of that.

So I think this problem is made more complicated by the fact that I’m creating an isometric view of the world by using orthographic projection. The following is the code I’m currently using the create the camera’s view matrix:

`

    public Vector3 position = Vector3.Transform(new Vector3(0, -10f, 10f), 
        Matrix.CreateRotationY(MathHelper.ToRadians(45)));
    public Vector3 lookAtVector = Vector3.Transform(new Vector3(0, 0, 0), 
        Matrix.CreateRotationY(MathHelper.ToRadians(45)));

    public Matrix ViewMatrix
    {
        get
        {
            var upVector = Vector3.UnitY;
            Matrix rotation = Matrix.CreateRotationY(MathHelper.ToRadians((float)angle));

            return Matrix.CreateLookAt(Vector3.Transform(position, rotation), Vector3.Transform(lookAtVector, rotation), upVector);
        }
    }

`

Which when I render a model with a texture on it, gives me something like this (which is what I want), and when rotating it simply rotates around the model’s center whilst maintaining the look at vector and looking directly at the center of the model (which isn’t what I want).

I’ve tried to visualized it as best as I could in this image. So as you can see as the camera rotates around the model it shouldn’t be looking at the center of the model but instead at a vector that would produce the same perspective as the image shown in the first link, but where a different point in world space would be at the center of the view (perhaps the model might not even be shown at some point) at each interval of the rotation, while maintaining the same isometric perspective.

If this was unclear I can try and find a better way to help visualize the desired effect.

as willmotil mentioned

store forward vector and reconstruct view matrix from it

    public Vector3 position = Vector3.Transform(new Vector3(0, -10f, 10f),
    Matrix.CreateRotationY(MathHelper.ToRadians(45)));
    public Vector3 lookAtVector = Vector3.Transform(new Vector3(0, 0, 0),
        Matrix.CreateRotationY(MathHelper.ToRadians(45)));

    Vector3 _forward;

    public void Init()
    {
        _forward = Vector3.Normalize(lookAtVector - position);
    }

    public Matrix ViewMatrix
    {
        get
        {
            var upVector = Vector3.UnitY;
            Matrix rotation = Matrix.CreateRotationY(MathHelper.ToRadians((float)angle));

            Vector3 newposition = Vector3.Transform(position, rotation);
            return Matrix.CreateLookAt(newposition, newposition + _forward, upVector);
        }
    }

Thanks for your suggestion, I’ll give it a go tomorrow and post the results. Our of curiosity why is it that we need to normalize the forward vector in this instance?

Another approach might be to use Cylindrical Coordinates and setting the target to position.x + 1.
This is what I use in my game to rotate around a target but it can be easily modified to accomodate your needs.

need not to normalize in this case
cough… just a habit.

Finally found some free time to test out this code and it worked perfectly, thanks for your help guys :slight_smile: