Camera rotation with a quaternion - math

I am having a problem with the maths of camera rotation, well more like I lack knowledge on this subject and can't find anything about it on the internet (read, most likely don't know the correct search keywords)
Anyway, this is what I am attempting to do (pseudo code):
RotateCamera(angle,axis){
Quaternion rotation = cam.getRotation();
Quaternion rot = new Quaternion();
rot.fromAngleNormalAxis(angle, axis);
rotation.multLocal(rot);
cam.setRotation(rotation);
}
update(float value){ // just to show what input I use the RotateCamera method for the directions
RotateCamera(value,Vector3f(0,1,0)) // left
RotateCamera(-value,Vector3f(0,1,0)) // right
RotateCamera(value,Vector3f(1,0,0)) // up
RotateCamera(-value,Vector3f(1,0,0)) // down
}
Now this works quite well but sometimes the cam will roll instead of only yaw/pitch. What is the correct way of doing this?

With just the bit of code given, it's hard to say for sure. But it looks like you've hard coded the axes of rotation into your update method. The thing about rotations (whether represented by quaternions or matrices) is that their multiplication isn't "commutative" meaning doing the same two rotations but in opposite orders does not give the same result.
It looks like you're assuming the camera is facing in the (0,0,1) direction, let's call it the z axis, with the y axis (0,1,0) coming out of the top of your head. As long as this assumption holds, you're axis of rotation for looking up, down, left and right will be (1,0,0), (1,0,0), (0,1,0) and (0,1,0) as they seem to be in your code snippet. But say you've just rotated 90 degrees to the left. This sends the camera's view from the (0,0,1) direction to the (1,0,0) direction. Now say you make an "up" rotation, which was coded to be around the (1,0,0) axis. This is a rotation around the same axis in which you're looking, and the effect will be a roll.
Does this address the issue? If so, you should code your axes of rotation w.r.t. the current direction the camera is facing.

Related

Unity raycast going random directions

Ray r = new Ray(this.transform.position, this.transform.eulerAngles);
RaycastHit hit;
if(Physics.Raycast(r, out hit, 3000, 256 /*layer 8*/ )){
That little bit of code won't give me a forward raycast, and I've searched for a number of solutions over multiple hours, to no avail.
So, the above won't give me a straight raycast out the front of the object and I don't know why. I figure it's probably an oversight.
The constructor for Ray takes an origin and a direction. transform.eulerAngles returns a vector of three angles around the x, y, and z axes. "Direction" might sound similar to angles, but it's not: the angles are rotation, not direction. The important distinction is that a direction vector "points" a certain way, but rotation describes how something is oriented. You could create a direction vector using the rotation information, but fortunately Unity can do this for you.
The easiest way to fix this is to use Unity's built-in way to get an object's forward direction vector (as seen in the Ray doc):
// Create a ray from the transform position along the transform's z-axis
Ray ray = new Ray(transform.position, transform.forward);
transform.forward gives you the forward direction vector of transform, meaning that the ray will be shot in the direction the object's facing.

how to translate 3d mesh, given a view direction and a change in cursor position

My question is similar to 3D Scene Panning in perspective projection (OpenGL) except I don't know how to compute the direction in which to move the mesh.
I have a program in which various meshes can be selected. Once a mesh is selected I want it to translate when click-dragging the cursor. When the cursor moves up, I want the mesh to move up, and so on for the appropriate direction. In other words, I want the mesh to translate in directions along the plane that is perpendicular to the viewing direction.
I have the Vector2 for the Delta (x,y) in cursor postion, and I have the Vector3 viewDirection of the camera and the center of the mesh. How can I figure out which way to translate the mesh in 3d space with the Delta and viewDirection? Will I need other information in order to to this calculation (such as the up, or eye)?
It doesn't matter if if the scale of the translation is off, I'm just trying to figure out the direction right now.
EDIT: for some reason I had a confusion about getting the up direction. Clearly it can be calculated by applying the camera rotation to the specified perspective up vector.
You'll need an additional vector, upDirection, which is the unit vector pointing "up" from your camera. You can now cross-product viewDirection and upDirection to get rightDirection, the vector pointing "right" from your camera.
You want to map y deltas to motion along upDirection (or -upDirection) and x deltas to motion in rightDirection. These vectors are in world-space.
You may want to scale the translation speed to match the mouse speed. If you are using perspective projection you'll want to scale the translation speed with your model's depth with respect to your camera (The further the object is from your camera, the faster you will need to move it if you want it to match the mouse.)

Rotating a vector in libgdx box2d, firing a cannon ball from a cannon

I have a cannon that fires a cannonball and smoke particle effect, i want the cannon ball to start at the end of the cannon, this i can do by adding the width of the cannon to its x position and adding the half the height to the cannon. This works fine when the cannon is unrotated but when i rotate the cannon its not in the correct position. This is what i use to try and rotate the vector.
Vector2 rotPos = cannon.position.tmp().add(cannon.bounds.width, cannon.bounds.height/2).rotate(cannon.angle);
How can i get a rotated vector that fires the cannon ball in the correct place. See image below.
UPDATE
I tried the below also, same result the ball is off to the left
Vector2 rotPos = world.CannonBody.getWorldVector( world.CannonBody.getPosition() );
The way that you've described the problem, you've solved it for only a single case. This really is just a math problem. Think about the direction you want to shoot, the barrel of the cannon, as the coordinates on a circle.
Since you know the angle, this is easy. Draw a circle with a dot in the center. Then draw a line from the center to the right edge. Then draw another line at a 45 degree angle up from the first line. Connect the two points on the edges with a straight line. You have a triangle now.
Lets call the 45 degree angle line 'r'. And we'll call the first line x, and the last line y.
You should have something that looks like this:
http://i.stack.imgur.com/MJNWZ.jpg
We know that sin(angleInRadians) = y/r. Doing a little algebra we can change this into r*sin(angleInRadians) = y
Boom, you have your y coordinate.
Almost the same thing: cos(angleInRadians) = x/r
So r*cos(angleInRadians) = x
There's your x coordinate.
The you can get the angle of a body directly from box2d, so that's easy. You just need to pick a value for 'r' that represents a correct radius for the circle that you're using to conceptualize the barrel of the cannon at a given angle. If the cannon rotates around the center of the circle, then r is the length of your cannon.
I had an issue which is similar to yours. Here's the question with an answer:
Android. How to move object in the direction it is facing (using Vector3 and Quaternion)
You need something like
translation.set(baseDirection).rot(modelInstance.transform).nor()

3d rotation around the origin

I know there are plenty of questions about 3d rotation that have been answered here but all of them seem to deal with rotational matrices and quaternions in OpenGL (and I don't really care if I get gimbal lock). I need to get 3d coordinates EX:(x,y,z) of a point that always must be the same distance, I'll call it "d" for now, from the origin. The only information I have as input is the deltax and deltay of the mouse across the screen. So far here is what I have tried:
First:
thetaxz+=(omousex-mouseX)/( width );
thetaxy+=(omousey-mouseY)/( height);
(thetaxy is the angle in radians on the x,y axis and thetaxz on the x,z axis)
(I limit both angles so that if they are less than or equal to 0 they equal 2*PI)
Second:
pointX=cos(thetaxz)*d;
pointY=sin(thetaxy)*d;
(pointX is the point's x coordinate and pointY is the y)
Third:
if(thetaxz)<PI){
pointZ=sqrt(sq(d)-sq(eyeX/d)-sq(eyeY/d));
}else{
pointZ=-sqrt(abs(sq(d)-sq(eyeX/d)-sq(eyeY/d)));
}
(sq() is a function that squares and abs() is an absolute value function)
(pointZ should be the point's z coordinate and it is except at crossing between the positive z hemisphere and negative z hemisphere. As it approaches the edge the point gets stretched further than the distance that it is always supposed to be at in the x and y and seemingly randomly around 0.1-0.2 radians of thetaxz the z coordinate becomes NAN or undefined)
I have thought about this for awhile, and truthfully I'm having difficulty warping my head around the concept of quaternions and rotational matrices however if you can show me how to use them to generate actual coordinates I would be glad to learn. I would still prefer it if I could just use some trigonometry in a few axis. Thank you in advance for any help and if you need more information please just ask.
Hint/last minute idea: I think it may have something to do with the z position affecting the x and y positions back but I am not sure.
EDIT: I drew a diagram:
If you truly want any success in this, you're going to have to bite the bullet and learn about rotation matrices and / or quaternion rotations. There may be other ways to do what you want, but rotation matrices and quaternion rotations are used simply because they are widely understood and among the simplest means of expressing and applying rotations to vectors. Any other representation somebody can come up with will probably be a more complex reformulation of one or both of these. In fact it can be shown rotation is a linear transformation and so can be expressed as a matrix. Quaternion rotations are just a simplified means of rotating vectors in 3D, and therefore have equivalent matrix representations.
That said, it sounds like you're interested in grabbing an object in your scene with a mouse click and rotating in a natural sort of way. If that's the case, you should look at the ArcBall method (there are numerous examples you may want to look over). This still requires you know something of quaternions. You will also find that an at least minimal comprehension of the basic aspects of linear algebra will be helpful.
Update: Based on your diagram and the comments it contains, it looks like all you are really trying to do is to convert Spherical Coordinates to Cartesian Coordinates. As long as we agree on the the notation, that's easy. Let θ be the angle you're calling XY, that is, the angle between the X axis rotated about the Z axis; this is called the azimuth angle and will be in the range [0, 2π) radians or [0°, 360°). Let Φ be an angle between the XY plane and your vector; this is called the elevation angle and will be in the range [-π/2, +π/2] or [-90°, +90°] and it corresponds to the angle you're calling the XZ angle (rotation in the XZ plane about the Y axis). There are other conventions, so make sure you're consistent. Anyway, the conversion is simply:
x = d∙cos(Φ)∙cos(θ)
y = d∙cos(Φ)∙sin(θ)
z = d∙sin(Φ)

Traveling along the surface of a sphere using quaternions

I'm programming a 3D game where the user controls a first-person camera, and movement is constrained to the inside surface of a sphere. I've managed to constrain the movement, but I'm having trouble figuring out how to manage the camera orientation using quaternions. Ideally the camera up vector should point along the normal of the sphere towards its center, and user should be able to free look around - as if we was always on the bottom of the sphere, no matter where he moves.
Presumably you have two vectors describing the camera's orienation. One will be your V'up describing which way is up relative to the camera orientation and the other will be your V'norm which will be the direction the camera is aimed. You will also have a position p', where your camera is located at some time. You define a canonical orientation and position given by, say:
Vup = <0, 1, 0>
Vnorm = <0, 0, 1>
p = <0, -1, 0>
Given a quaternion rotation q you then apply your rotation to those vectors to get:
V'up = qVupq-1
V'norm = qVnormq-1
p' = qpq-1
In your particular situation, you define q to incrementally accumulate the various rotations that result in the final rotation you apply to the camera. The effect will be that it looks like what you're describing. That is, you move the camera inside a statically oriented and positioned sphere rather than moving the spehere around a statically oriented and positioned camera.
Each increment is computed by a rotation of some angle θ about the vector V = V'up x V'norm.
Quaternions are normally used to avoid gimbal lock in free space motion (flight sims, etc.). In your case, you actually want the gimbal effect, since a camera that is forced to stay upright will inevitably behave strangely when it has to point almost straight up or down.
You should be able to represent the camera's orientation as just a latitude/longitude pair indicating the direction the camera is pointing.

Resources