Determine position in front of quaternion with GLM? - c++

Is there a way to calculate the XYZ position in front of a quaternion (XYZW) rotation, preferably using GLM?
I know the Quat rotation and the Position of the object I want to calculate the position in front of.
I know how to calculate the position in front of a rotation matrix where you have a Front vector, Up vector and Right vector, but in this case I only have XYZW values (where W is always 0, I never see it becomming 1..?)
In very short:
The data I have: Quat (X Y Z W) and Position(X Y Z) and I want to calculate PositionInFront(Position, Quat, Distance, &X, &Y, &Z)
How to accomplish this goal?
I tried a cast to 3x3matrix and perform the Up,Right,Front (because a 3x3 matrix cast is these values, right?) calculations but they do not return the correct positions.
Or would it be possible to determine the objects Z Angle? (rotation around world Z / height axis only)

It seemed that there were 2 more quaternion structures for the vehicle which I forgot to use. and those 3 are the complete set needed for the Front,Right,Up calculation formula:
float offX = 10.0f;
float offY = 0.0f;
float offZ = 0.0f;
float x = offX * info.Rotation.Front.x + offY * info.Rotation.Right.x + offZ * info.Rotation.Up.x + info.Pos.x;
float y = offX * info.Rotation.Front.y + offY * info.Rotation.Right.y + offZ * info.Rotation.Up.y + info.Pos.y;
float z = offX * info.Rotation.Front.z + offY * info.Rotation.Right.z + offZ * info.Rotation.Up.z + info.Pos.z;
float Angle = (atan2(x-info.Pos.x, y-info.Pos.y) * 180.0f / PI);

Related

Finding the new target of camera relative to a direction in 3D space (bad title) C++

I have a camera set up with the coordinates of 0, 0, 1000 and a cube at 0, 0, 0. There is a camera position vector, rotation vector and target vector.
When finding the target, in 2d space I would use:
newx = cos(angle); // this will be very small so i would multiply it by 100 or something idk
newy = sin(angle); // same and so on
So in 3d space I'm assuming that I would use:
newx = cos(angle);
newy = sin(angle);
newz = tan(angle);
But because I'm using the mouse to find the x and y direction the z rotation is always 0:
float x_diff = (WIDTH/2) - mousePos.x;
x_diff /= WIDTH;
float y_diff = (HEIGHT/2)- mousePos.y;
y_diff /= HEIGHT;
cameraRotation.x += /* too small of a number so multiply by 5 */ 5 * (FOV * x_diff);
cameraRotation.y += 5 * (FOV * y_diff);
cameraRotation.z += ???;
and so the target z will always be 0.
I could be doing this whole thing completely wrong I don't know.
But to sum it, up i need help calculating the cameras target (FOV: 90) for its rotation in 3D space.

OpenGL Spaceship thruster is not circular at base

I am developing a space shooter game using OpenGL. Trying to create a thruster effect for the player's spaceship using particles. I am facing a problem where the base of the thruster is not circular under some angles of the spaceship. You can see the effect in the video.
This is the code for calculating the circular base :
float random = fmod(static_cast<float>(rand()) / 100.0, mSize);
glm::vec3 radius = (mUp * random) + (mRight * random);
float angle = (float)i / (float)mNumOfInstances * 360.0f;
float x = mPos.x + glm::cos(angle) * radius.x;
float y = mPos.y + glm::sin(angle) * radius.y;
float z = mPos.z + glm::cos(angle) * radius.z;
particle.Position = glm::vec3(x, y, z);
Can someone suggest any corrections to this code to fix the problem?
The solution was the following for anyone having the same problem:
glm::vec3 up = (mUp * random);
glm::vec3 right = (mRight * random);
particle.Position = mPos + glm::cos(angle) * up + sin(angle) * right;
mUp is the Up vector, mRight is the right vector of the spaceship, angle is the angle for the specific point (0-360) and random is a random radius because I want a filled circle.

Problems rotating opengl camera

I cannot understand the math behind this problem, I am trying to create an FPS camera where I can look freely with my mouse input.
I am trying to rotate and position my lookat point with 180 degrees of freedom. I understand the easier solution is to glRotate the world to fit my perspective, but I do not want this approach. I am fairly unfamiliar with the trigonometry involved here and cannot figure out how to solve this problem the way I want to...
here is my attempt to do this so far...
code to get mouse coordinates relative to the center of the window, then process it in my camera object
#define DEG2RAD(a) (a * (M_PI / 180.0f))//convert to radians
static void glutPassiveMotionHandler(int x, int y) {
glf centerX = WinWidth / 2; glf centerY = WinHeight / 2;//get windows origin point
f speed = 0.2f;
f oldX = mouseX; f oldY = mouseY;
mouseX = DEG2RAD(-((x - centerX)));//get distance from 0 and convert to radians
mouseY = DEG2RAD(-((y - centerY)));//get distance from 0 and convert to radians
f diffX = mouseX - oldX; f diffY = mouseY - oldY;//get difference from last frame to this frame
if (mouseX != 0 || mouseY != 0) {
mainCamera->Rotate(diffX, diffY);
}
Code to rotate the camera
void Camera::Rotate(f angleX, f angleY) {
Camera::refrence = Vector3D::NormalizeVector(Camera::refrence * cos(angleX)) + (Camera::upVector * sin(angleY));//rot up
Camera::refrence = Vector3D::NormalizeVector((Camera::refrence * cos(angleY)) - (Camera::rightVector * sin(angleX)));//rot side to side
};
Camera::refrence is our lookat point, processing the lookat point is handled as follows
void Camera::LookAt(void) {
gluLookAt(
Camera::position.x, Camera::position.y, Camera::position.z,
Camera::refrence.x, Camera::refrence.y, Camera::refrence.z,
Camera::upVector.x, Camera::upVector.y, Camera::upVector.z
);
};
The camera is defined by a position point (position) a target point (refrence) and a up-vector upVector. If you want to change the orientation of the camera, then you've to rotate the direction vector from the position (position) to the target (refrence) rather then the target point by a Rotation matrix.
Note, since the 2 angles are angles which should change an already rotated view, you've to use a rotation matrix, to rotate the vectors which point in an arbitrary direction.
Write a function which set 3x3 rotation matrix around an arbitrary axis:
void RotateMat(float m[], float angle_radians, float x, float y, float z)
{
float c = cos(angle_radians);
float s = sin(angle_radians);
m[0] = x*x*(1.0f-c)+c; m[1] = x*y*(1.0f-c)-z*s; m[2] = x*z*(1.0f-c)+y*s;
m[3] = y*x*(1.0f-c)+z*s; m[4] = y*y*(1.0f-c)+c; m[5] = y*z*(1.0f-c)-x*s;
m[6] = z*x*(1.0f-c)-y*s; m[7] = z*y*(1.0f-c)+x*s; m[8] = z*z*(1.0f-c)+c };
}
Write a function which rotates a 3 dimensional vector by the matrix:
Vector3D Rotate(float m[], const Vector3D &v)
{
Vector3D rv;
rv.x = m[0] * v.x + m[3] * v.y + m[6] * v.z;
rv.y = m[1] * v.x + m[4] * v.y + m[7] * v.z;
rv.z = m[2] * v.x + m[5] * v.y + m[8] * v.z;
return rv;
}
Calculate the vector form the position to the target:
Vector3D los = Vector3D(refrence.x - position.x, refrence.y - position.y, refrence.z - position.z);
Rotate all the vectors around the z axis of the world by angleX:
float rotX[9];
RotateMat(rotX, angleX, Vector3D(0, 0, 1));
los = Rotate(rotX, los);
upVector = Rotate(rotX, upVector);
Rotate all the vectors around the current y axis of the view by angleY:
float rotY[9];
RotateMat(rotY, angleY, Vector3D(los.x, los.y, 0.0));
los = Rotate(rotY, los);
upVector = Rotate(rotY, upVector);
Calculate the new target point:
refrence = Vector3D(position.x + los.x, position.y + los.y, position.z + los.z);
U_Cam_X_angle is left right rotation.. U_Cam_Y_angle is up down rotation.
view_radius is the view distance (zoom) to U_look_point_x, U_look_point_y and U_look_point_z.
This is ALWAYS a negative number! This is because you are always looking in positive direction. Deeper in the screen is more positive.
This is all in radians.
The last three.. eyeX, eyeY and eyeZ is where the camera is in 3D space.
This code is in VB.net. Find a converter online for VB to C++ or do it manually.
Public Sub set_eyes()
Dim sin_x, sin_y, cos_x, cos_y As Single
sin_x = Sin(U_Cam_X_angle + angle_offset)
cos_x = Cos(U_Cam_X_angle + angle_offset)
cos_y = Cos(U_Cam_Y_angle)
sin_y = Sin(U_Cam_Y_angle)
cam_y = Sin(U_Cam_Y_angle) * view_radius
cam_x = (sin_x - (1 - cos_y) * sin_x) * view_radius
cam_z = (cos_x - (1 - cos_y) * cos_x) * view_radius
Glu.gluLookAt(cam_x + U_look_point_x, cam_y + U_look_point_y, cam_z + U_look_point_z, _
U_look_point_x, U_look_point_y, U_look_point_z, 0.0F, 1.0F, 0.0F)
eyeX = cam_x + U_look_point_x
eyeY = cam_y + U_look_point_y
eyeZ = cam_z + U_look_point_z
End Sub

Determining texture co-ordinates across a geodesic sphere

I've generated a geodesic sphere for opengl rendering following a question on here and I'm trying to put texture on it. I came up with the following code by reversing an algorithm for a point on a sphere:
//complete circle equation is as follows
///<Summary>
///x = r * sin(s) * sin(t)
///y = r* cos(t)
///z = r * cos(s) * sin(t)
///</Summary>
float radius = 1.0f;
//T (height/latitude) angle
float angleT = acos(point.y / radius) ;
//S (longitude )angle
float angleS = ( asin(point.x / (radius * sin(angleT)))) + (1.0f* M_PI);
float angleS2 =( acos(point.z / (radius * sin(angleT)))) + (1.0f * M_PI);
//Angle can be 0-PI (0-180 degs), divide by this to get 0-1
angleT = angleT / (M_PI);
//Angle can be 0-2PI (0-360 degs)S
angleS = angleS / ( M_PI *2 );
angleS2 = angleS2 / ( M_PI *2 );
//Flip the y co-ord
float yTex = 1 - angleT;
float xTex = 0.0f;
//I have found that angleS2 is valid 0.5-1.0, and angleS is valid (0.3-0.5)
if (angleS < 0.5f)
{
xTex = angleS;
}
else
{
xTex = angleS2;
}
return glm::vec2( xTex , yTex);
As you can see, I've found that both versions of calculating the S angle have limited valid ranges.
float angleS = ( asin(point.x / (radius * sin(angleT)))) + (1.0f* M_PI);
float angleS2 =( acos(point.z / (radius * sin(angleT)))) + (1.0f * M_PI);
S1 is gives valid answers between x texture co-ords 0.3 and 0.5 and S2 gives valid answers for between x texture co-ords 0.5 and 1.0 (Conversion to co-ords omitted above but present in first code example). Why is it that neither formula is giving me valid answers for under 0.3?
Thanks
Will
Correct on this side
The weird border between working and not, probably caused by opengl's interpolation
Reversed section
The image being used
Edit: Here is the seam
The equations you use to calculate the longitude angles are not correct seeing what you are trying to accomplish. For the longitude angle, the range you require is 0-360 degrees, which can not be obtained through asin or acos functions, because those functions only return results between -90 and 90 degrees or 0 to 180 degrees. You can, however, use the atan2 function, which returns values from the correct interval. The code I've been working with for the past 2 years is the following:
float longitude = atan2f(point.x, point.z) + (float)M_PI;
This equation will map the horizontal center of the texture in the direction of positive Z axis. If you want the horizontal center of the texture to be in the direction of positive X axis, add M_PI / 2.0.

Stepping between spherical coords (OpenGL, C++, GLUT)

I have defined 2 points on the surface of a sphere using spherical coordinates.
// define end point positions
float theta_point_1 = (5/10.0)*M_PI;
float phi_point_1 = (5/10.0)*2*M_PI;
float x_point_1 = Radius * sin(theta_point_1) * cos(phi_point_1);
float y_point_1 = Radius * sin(theta_point_1) * sin(phi_point_1);
float z_point_1 = Radius * cos(theta_point_1);
float theta_point_2 = (7/10.0)*M_PI;
float phi_point_2 = (1/10.0)*2*M_PI;
float x_point_2 = Radius * sin(theta_point_2) * cos(phi_point_2);
float y_point_2 = Radius * sin(theta_point_2) * sin(phi_point_2);
float z_point_2 = Radius * cos(theta_point_2);
// draw end points
void end_points ()
{
glColor3f (1.0, 1.0, 1.0);
glPointSize(25.0);
glBegin(GL_POINTS);
glVertex3f(x_point_1,y_point_1,z_point_1);
glVertex3f(x_point_2,y_point_2,z_point_2);
glEnd();
}
To step between the two points, I do the following:
find the difference between theta_points_1,2 and phi_points_1,2
divide the differences by 'n' (yielding 's')
redraw 'n' times, while stepping up the theta and phi by 's' each time
In the following, I've defined the differences between my theta and phi values, divided them, and then redraw them.
// begining spherical coords
float theta_point_1_value=5;
float phi_point_1_value=5;
// ending sperical coords
float theta_point_2_value=7;
float phi_point_2_value=1;
// dividing the difference evenly
float step_points=30;
float step_theta = 2/step_points;
float step_phi = 4/step_points;
// step between spherical coordinates
void stepping_points ()
{
glColor3f (1.0, 0.0, 0.0);
for (int i = 1; i < step_points; i++)
{
float theta = (theta_point_1_value/10.0)*M_PI;
float phi = (phi_point_1_value/10.0)*2*M_PI;
float x = Radius * sin(theta) * cos(phi);
float y = Radius * sin(theta) * sin(phi);
float z = Radius * cos(theta);
glPushMatrix();
glTranslatef(x,y,z);
glutSolidSphere (0.05,10,10);
glPopMatrix();
}
glEnd();
}
Now I understand, this displays 30 solid spheres at the same position. Because I have NOT included 'step_theta' or 'step_phi' in any of the redraws.
And that is the root of my question. How do I employ 'step_theta' and 'step_phi' in my redraws?
What I want to do is say something like this at the top of my 'for' loop:
for (int i = 1; i < step_points; i++)
{
float theta_point_1_value = (theta_point_1_value+step_theta);
float phi_point_1_value = (phi_point_1_value+step_phi);
float theta = (theta_point_1_value/10.0)*M_PI;
float phi = (phi_point_1_value/10.0)*2*M_PI;
float x = Radius * sin(theta) * cos(phi);
float y = Radius * sin(theta) * sin(phi);
float z = Radius * cos(theta);
glPushMatrix();
glTranslatef(x,y,z);
glutSolidSphere (0.05,10,10);
glPopMatrix();
}
The above will redraw 30 solid spheres, but they don't show between my defined end points. It's pretty clear that either my math or syntax is screwy (or more than likely, both are).
Hint: What is the range of your loop variable, i? What do you want the range of your step_theta and step_phi to be?
When you declare a variable inside the loop, it goes out of scope and is destructed after every iteration. As such, only the value of i changes between your loop iterations.
Also: Consider using a vector/point class. (x_point_1, y_point_1) is not C++ :).
If you want consistent timing regardless of frame rate, you need to track the passage of time and use that to control how far you interpolate between the two points. Remember the start time and calculate the desired end time, then each frame, calculate (float)(now-start)/(end-start). This will give you a value between 0.0 and 1.0. Multiply that value by the delta of each spherical coordinate and add their start angles and you'll get what angles you need to be at now.