Camera flip problem - c#

I'm programming a game in C# using the XNA3.1 engine. However I'm having a small issue with my camera, basically my camera tends to "flip" when it rotates more than 180 degrees on its roll (when the camera reaches 180 degrees, it seems to flip back to 0 degrees). The code for obtaining the view matrix is as follows:
Globals.g_GameProcessingInfo.camera.viewMat = Matrix.CreateLookAt(Globals.g_GameProcessingInfo.camera.target.pos, Globals.g_GameProcessingInfo.camera.LookAt, up); //Calculate the view matrix
The Globals.g_GameProcessingInfo.camera.LookAt variable the position 1 unit directly in front of the camera, relative to the rotation of the camera, and the "up" variable is obtained with the following function:
static Vector3 GetUp() //Get the up Vector of the camera
{
Vector3 up = Vector3.Zero;
Quaternion quat = Quaternion.Identity;
Quaternion.CreateFromYawPitchRoll(Globals.g_GameProcessingInfo.camera.target.rot.Y, Globals.g_GameProcessingInfo.camera.target.rot.X, Globals.g_GameProcessingInfo.camera.target.rot.Z, out quat);
up.X = 2 * quat.X * quat.Y - 2 * quat.W * quat.Z; //Set the up x-value based on the orientation of the camera
up.Y = 1 - 2 * quat.X * quat.Z - 2 * quat.Z * quat.Z; //Set the up y-value based on the orientation of the camera
up.Z = 2 * quat.Z * quat.Y + 2 * quat.W * quat.X; //Set the up z-value based on the orientation of the camera
return up; //Return the up Vector3
}

I got same problems in OpenGL with gluLookAt. I fixed that problem with my own camera class:
void Camera::ComputeVectors()
{
Matrix4x4 rotX, rotZ;
Quaternion q_x, q_y, q_z;
Quaternion q_yx, q_yz;
q_x.FromAngleAxis(radians.x, startAxisX);
q_y.FromAngleAxis(radians.y, startAxisY);
q_z.FromAngleAxis(radians.z, startAxisZ);
q_yx = q_y * q_x;
q_yx.ToMatrix(rotZ);
q_yz = q_y * q_z;
q_yz.ToMatrix(rotX);
axisX = startAxisX;
axisZ = startAxisZ;
axisX.Transform(rotX);
axisZ.Transform(rotZ);
axisY = axisX.Cross(axisZ);
position = startPosition;
position -= center;
position.Transform(q_yx);
position += center;
}
It is maybe overcomplicated, but working. axisY is your up vector.
Full code listing is at:
http://github.com/filipkunc/opengl-editor-cocoa/blob/master/PureCpp/MathCore/Camera.cpp
Hope it helps.

This is probably slower but the only way I know to do with would be the with the rotation matrix for 3D. Wikipedia Link
Where
and U = (Camera.position - Camera.lookat).norm
... Now, I believe that would give you the rotation part of the view matrix. However, I'm not 100% on it. I'm still looking into this though.

meh was hoping to see a tan in there somewhere.
can you link to where you got your equation from please?
(am at work and really don;t want to sit down myself and derive it)
how are you setting your camera rotation? are you sure nothing is going on there?

I'm a bit unsure about the math in your GetUp method. Could you elaborate on the math behind it?
In my lookat camera I initialize my up-vector once and then rotate that vector using a quaternion. This removes the possibility of trying to do a cross-product on parallel vectors in order to calculate the up vector.
Some semicode to clarify perhaps:
var up = Vector3.Up;
var target = <some point in space>;
var rotation = <current rotation quaternion>;
var forward = target - position;
forward = Vector3.Transform(forward, rotation);
var updatedPosition = target - forward;
var updatedUp = Vector3.Transform(up, rotation);
var view = Matrix.CreateLookAt(updatedPosition, target, updatedUp);

Since I wasn't satisfied with the answers here already, I had to figure this out myself.
What I discovered is it's actually quite simple. Just do this:
Matrix ypr = Matrix.CreateFromYawPitchRoll(yaw, pitch, roll);
Vector3 up = Vector3.Transform(Vector3.Up, ypr);
"up" is the direction you want.

Related

Not able to Clamp my camera rotation value

I made a camera that rotates around an object... Everything is working fine. But I was not able to clamp or restrict the camera rotation. Here's the code..
//First - Get the Initial Position
if (Input.GetMouseButtonDown(0))
{
mPreviousPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
}
//Second - the difference amount and change in x
if (Input.GetMouseButton(0))
{
Vector3 newPosition = mCamRef.ScreenToViewportPoint(Input.mousePosition);
Vector3 direction = mPreviousPosition - newPosition;
float rotationAroundYAxis = -direction.x * 180;
mCamRef.transform.position = mTargetToRotateAround.position;
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -60f,60f);
mCamRef.transform.rotation = Quaternion.Euler(Vector3.up * rotationAroundYAxis);
mCamRef.transform.Translate(new Vector3(mDistanceToTarget.x, mDistanceToTarget.y, -mDistanceToTarget.z));
mPreviousPosition = newPosition;
}
You are clamping
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -0.6f, 0.6f);
but then use it for Transform.Rotate which rotates from the current rotation about the given amount => you always rotate something.
You would probably rather use e.g. Quaternion.Euler
mCamRef.transform.rotation = Quaternion.Euler(Vector3.up * rotationAroundYAxis);
However, note that clamping a rotation using +- 0.6° makes barely any sense ...
From you comments you want to clamp to +-60° so rather use
rotationAroundYAxis = Mathf.Clamp(rotationAroundYAxis, -60, 60);
Though I still don't understand how you want to get a rotation in angles from a direction vector ...

Quaternion.Lerp not working properly in Unity3d

I'm using Quaternion.Lerp to rotate a joint with a certain angle, but when I use the below code I find the joint rotating very far although I specified it to rotate with only 5. Any thoughts please?
newRot.y += currentTransform.localRotation.y + 5f;
blendWeight = 0;
if ( blendWeight < 1)
{
animationRotation = currentTransform.transform.localRotation;
newRotation = Quaternion.Euler(newRot.x, newRot.y, newRot.z);
blendWeight += Time.deltaTime/0.9f;
currentTransform.transform.localRotation = Quaternion.Lerp (animationRotation,newRotation, blendWeight);
}
where newRot is a Vector3
If you want to add 5 degrees to y, you must use eulerAngles and not directly rotation (which il a quaternion). Generaly speaking you should never set the xyzw components of a quaternion.
If you want y slowly rotates an object, consider using RotateTowards (for a given target orientation) or transform.Rotate (for a given speed).

How can I rotate a vector (centripetal force)?

I'm trying to implement centripetal force in a programming language.
I saw some videos teaching the theory. But I dont know how to apply that in a programming language.
If I understand I have to apply centripetal force ac = v²/r to the velocity vector. But I dont know exactly how to proceed.
I have two game objects, one depicting Earth, other depicting Moon. What I wanted is to translate the moon around earth and using a button to "cut/cancel" the centripetal force in order to the moon get out to the earth's orbit.
I have no clue how to start that.
All I know is to rotate like this:
velocity.x = Mathf.Cos(Time.time) * earth_moon_radius;
velocity.z = Mathf.Sin(Time.time) * earth_moon_radius;
moon.transform.position = velocity;
But how to apply centripetal force as described above?
If you just want to have the moon rotating around earth and some trigger to release the moon, it's easier to use rotation around a center instead of forces. Given the following GameObject hierarchy:
Center (MoonRotator attached)
-- Moon
-- Earth
public class MoonRotator : MonoBehaviour
{
public bool cancelCentripetalForce = false;
public Vector3 angularVelocity = new Vector3 (0f, 0f, 100f);
public GameObject moon;
void Update () {
if (cancelCentripetalForce) {
Vector3 radius = moon.transform.position - transform.position;
Vector3 angularVelocityRadians = Mathf.Deg2Rad * angularVelocity;
moon.rigidbody.velocity = Vector3.Cross (angularVelocityRadians, radius);
moon.transform.parent = null;
Destroy (this);
} else {
Vector3 rot = transform.rotation.eulerAngles + angularVelocity * Time.deltaTime;
transform.rotation = Quaternion.Euler (rot);
}
}
}
If cancelCentripetalForce is set true Moon stops travelling around earth but proceeds with its current tangential velocity. This is given as:
v = ω × r
Earth has localPosition (0, 0, 0) and Moon is in this example located in the x-y plane rotating around the z axis.
If you want to cancel the force, add an opposing force vector that is based on your object's linear velocity and current direction.
So I have an object pointing straight along the Z axis. The object's 'forward' vector is 0, 0, 1. Do 1 - Math.abs(forward.x), same for y and z to get 1, 1, 0 when you're pointing forward along the Z axis. You want the direction you're pointing in to be 0'd so that the inertia from that direction is not damped in any way. Now you can apply a cancellation force in any direction that you are NOT pointed in.
This means that if your object is moving in any direction in world space that it's not facing in you can easily apply a cancellation force that is multiplied by the object's linear velocity to get circular motion that uses forces instead of directly setting velocity.
Another way you can do it is solve for V by manually setting it, then find radius using V=RW. You should know V and R or W. Now you can find the force necessary to keep the orbit stable around a point, rather than adding inertia from every frame.

C# XNA Mouse position projected to 3D plane

I'm working on a 3D XNA project, and I've been thinking about this problem for like 2 weeks.
So I just decided to ask you.
Basically I have a flat plane and i want to project the mouse position to that plane, but how?
I tried many ways to do it, calculated angles...
But i figured out, that the distance must effect on the X position, maybe some math is needed what I've never heard before.
I did some code few years ago which returns the position as Vector3(x,y,z), given mouse state:
private Vector3 FindWhereClicked(MouseState ms)
{
Vector3 nearScreenPoint = new Vector3(ms.X, ms.Y, 0);
Vector3 farScreenPoint = new Vector3(ms.X, ms.Y, 1);
Vector3 nearWorldPoint = device.Viewport.Unproject(nearScreenPoint, cam.projectionMatrix, cam.viewMatrix, Matrix.Identity);
Vector3 farWorldPoint = device.Viewport.Unproject(farScreenPoint, cam.projectionMatrix, cam.viewMatrix, Matrix.Identity);
Vector3 direction = farWorldPoint - nearWorldPoint;
float zFactor = -nearWorldPoint.Y / direction.Y;
Vector3 zeroWorldPoint = nearWorldPoint + direction * zFactor;
return zeroWorldPoint;
}
device is an instance of GraphicsDevice.
Hope it works for you.

XNA: get Vector3 from Matrix

I thought I understood matrix math well enough, but apparently I'm clueless
Here's the setup:
I have an object at [0,0,0] in world space. I have a camera class controlled by mouse movements to rotate and zoom around the object such that it always looks at it. Here is how I calculate my viewMatrix from the camera:
public Matrix viewMatrix {
get {
return
Matrix.CreateFromAxisAngle(Vector3.Up, rotAngle)
* Matrix.CreateFromAxisAngle(Vector3.Left, pitchAngle)
* Matrix.CreateTranslation(0, 0, distance)
;
}
}
I need to be able to get the position of the camera in world space so I can get its distance from the box--particularly its distance from each face of the box. How can I get the camera's xyz position in world space coords?
I've tried:
// all of these only return [0, 0, distance];
Vector3 pos = Vector3.Transform(Vector3.Zero, viewMatrix);
Vector3 pos = viewMatrix.Translation;
Vector3 pos = new Vector3(viewMatrix.M41, viewMatrix.M42, viewMatrix.M43);
It seems like the rotation information is being lost somehow. The strange thing is that the viewMatrix code works perfectly for positioning the camera!
or to simplify slightly:
Vector3 pos = Matrix.Invert(view).Translation;
Once again, I figure out the problem within seconds of posting the question:
I needed to invert the view matrix. The rotation info was being lost because it plays no part in the distance calculation until the view matrix is inverted. The rotation was at the wrong "end" of the transformation.
Vector3 pos = Vector3.Transform(Vector3.Zero, Matrix.Invert(viewMatrix));

Categories