I'm trying to write a 4*4 float matrix class to create a 3D space with model, view, and projection matrices. In its current state when i try to rotate the view matrix, it seems to also apply translation, and the space gets distorted (as if it was squeezed). The projection, view, and model matrix multiplication is done in the vertex shader.
Edit5: The non-functioning state of the transformation functions is found below:
public class Mat4f {
public float m00, m10, m20, m30,
m01, m11, m21, m31,
m02, m12, m22, m32,
m03, m13, m23, m33;
public Mat4f() {
loadIdentity();
}
public Mat4f loadIdentity() {
m00 = 1.0f; m10 = 0.0f; m20 = 0.0f; m30 = 0.0f;
m01 = 0.0f; m11 = 1.0f; m21 = 0.0f; m31 = 0.0f;
m02 = 0.0f; m12 = 0.0f; m22 = 1.0f; m32 = 0.0f;
m03 = 0.0f; m13 = 0.0f; m23 = 0.0f; m33 = 1.0f;
return this;
}
public Mat4f store(FloatBuffer buffer) {
buffer.put(m00);
buffer.put(m01);
buffer.put(m02);
buffer.put(m03);
buffer.put(m10);
buffer.put(m11);
buffer.put(m12);
buffer.put(m13);
buffer.put(m20);
buffer.put(m21);
buffer.put(m22);
buffer.put(m23);
buffer.put(m30);
buffer.put(m31);
buffer.put(m32);
buffer.put(m33);
buffer.flip();
return this;
}
public Mat4f loadPerspective(float fov, float ratio, float near, float far) {
m11 = (float) (1.0f / (Math.tan(fov / 2.0f)));
m00 = m11 / ratio;
m22 = -(far + near) / (far - near);
m23 = -1.0f;
m32 = -2.0f * far * near / (far - near);
m33 = 0.0f;
return this;
}
public Mat4f translate(float x, float y, float z) {
m30 = x;
m31 = y;
m32 = z;
return this;
}
public Mat4f scale(float x, float y, float z) {
m00 = x;
m11 = y;
m22 = z;
return this;
}
public Mat4f rotateX(float x) {
m11 = (float) Math.cos(x);
m12 = (float) Math.sin(x);
m21 = (float) -(Math.sin(x));
m22 = (float) Math.cos(x);
return this;
}
public Mat4f rotateY(float y) {
m00 = (float) Math.cos(y);
m02 = (float) -(Math.sin(y));
m20 = (float) Math.sin(y);
m22 = (float) Math.cos(y);
return this;
}
public Mat4f rotateZ(float z) {
m00 = (float) Math.cos(z);
m01 = (float) Math.sin(z);
m10 = (float) -(Math.sin(z));
m11 = (float) Math.cos(z);
return this;
}
}
And the proper way to do those is as follows:
public Mat4f translate(float x, float y, float z, Mat4f dest) {
dest.m00 = m00;
dest.m01 = m01;
dest.m02 = m02;
dest.m03 = m03;
dest.m10 = m10;
dest.m11 = m11;
dest.m12 = m12;
dest.m13 = m13;
dest.m20 = m20;
dest.m21 = m21;
dest.m22 = m22;
dest.m23 = m23;
dest.m30 = m00 * x + m10 * y + m20 * z + m30;
dest.m31 = m01 * x + m11 * y + m21 * z + m31;
dest.m32 = m02 * x + m12 * y + m22 * z + m32;
dest.m33 = m03 * x + m13 * y + m23 * z + m33;
return this;
}
public Mat4f translate(float x, float y, float z) {
return translate(x, y, z, this);
}
public Mat4f scale(float x, float y, float z, Mat4f dest) {
dest.m00 = m00 * x;
dest.m01 = m01 * x;
dest.m02 = m02 * x;
dest.m03 = m03 * x;
dest.m10 = m10 * y;
dest.m11 = m11 * y;
dest.m12 = m12 * y;
dest.m13 = m13 * y;
dest.m20 = m20 * z;
dest.m21 = m21 * z;
dest.m22 = m22 * z;
dest.m23 = m23 * z;
dest.m30 = m30;
dest.m31 = m31;
dest.m32 = m32;
dest.m33 = m33;
return this;
}
public Mat4f scale(float x, float y, float z) {
return scale(x, y, z, this);
}
public Mat4f rotateX(float x, Mat4f dest) {
float cos = (float) Math.cos(x);
float sin = (float) Math.sin(x);
float rm11 = cos;
float rm12 = sin;
float rm21 = -sin;
float rm22 = cos;
float nm10 = m10 * rm11 + m20 * rm12;
float nm11 = m11 * rm11 + m21 * rm12;
float nm12 = m12 * rm11 + m22 * rm12;
float nm13 = m13 * rm11 + m23 * rm12;
dest. m20 = m10 * rm21 + m20 * rm22;
dest.m21 = m11 * rm21 + m21 * rm22;
dest.m22 = m12 * rm21 + m22 * rm22;
dest. m23 = m13 * rm21 + m23 * rm22;
dest.m10 = nm10;
dest.m11 = nm11;
dest.m12 = nm12;
dest.m13 = nm13;
return this;
}
public Mat4f rotateX(float x) {
return rotateX(x, this);
}
public Mat4f rotateY(float y, Mat4f dest) {
float cos = (float) Math.cos(y);
float sin = (float) Math.sin(y);
float rm00 = cos;
float rm02 = -sin;
float rm20 = sin;
float rm22 = cos;
float nm00 = m00 * rm00 + m20 * rm02;
float nm01 = m01 * rm00 + m21 * rm02;
float nm02 = m02 * rm00 + m22 * rm02;
float nm03 = m03 * rm00 + m23 * rm02;
dest.m20 = m00 * rm20 + m20 * rm22;
dest.m21 = m01 * rm20 + m21 * rm22;
dest.m22 = m02 * rm20 + m22 * rm22;
dest.m23 = m03 * rm20 + m23 * rm22;
dest.m00 = nm00;
dest.m01 = nm01;
dest.m02 = nm02;
dest.m03 = nm03;
return this;
}
public Mat4f rotateY(float y) {
return rotateY(y, this);
}
public Mat4f rotateZ(float z, Mat4f dest) {
float cos = (float) Math.cos(z);
float sin = (float) Math.sin(z);
float rm00 = cos;
float rm01 = sin;
float rm10 = -sin;
float rm11 = cos;
float nm00 = m00 * rm00 + m10 * rm01;
float nm01 = m01 * rm00 + m11 * rm01;
float nm02 = m02 * rm00 + m12 * rm01;
float nm03 = m03 * rm00 + m13 * rm01;
dest.m10 = m00 * rm10 + m10 * rm11;
dest.m11 = m01 * rm10 + m11 * rm11;
dest.m12 = m02 * rm10 + m12 * rm11;
dest.m13 = m03 * rm10 + m13 * rm11;
dest.m00 = nm00;
dest.m01 = nm01;
dest.m02 = nm02;
dest.m03 = nm03;
return this;
}
public Mat4f rotateZ(float z) {
return rotateZ(z, this);
}
To modify the matrices I used the following order of transformations:
public void transform() {
mMat.loadIdentity();
mMat.translate(position.x, position.y, position.z);
mMat.rotateX((float) Math.toRadians(orientation.x));
mMat.rotateY((float) Math.toRadians(orientation.y));
mMat.rotateZ((float) Math.toRadians(orientation.z));
mMat.scale(scale.x, scale.y, scale.z);
}
public void updateCamera() {
Vec3f position = World.camera.getPosition();
vMat.loadIdentity();
vMat.rotateX((float) Math.toRadians(World.camera.getPitch()));
vMat.rotateY((float) Math.toRadians(World.camera.getYaw()));
vMat.translate(-position.x, -position.y, position.z);
}
Edit: the perspective projection is fine, and so is the translation, but if i store the model matrix in a Mat4f, then models' rotation follows the camera's one.
Edit2: The model's orientation no longer follows the camera rotation when I use Mat4f as a model matrix. The projection matrix, translation, and scaling works well.
Edit3: Edited the code, the rotation applied is not a full circle rotation, the model swings left and right.
Edit4: I have attempted doing the rotation with matrix multiplication
Your matrix class does not implement the composition of transformations. Each of your matrix method just overwrites certain elements.
For example, look at the following sequenc of operations:
translate(1,1,1);
rotateX(45);
translate(1,1,1);
Such a sequence mathematically should be represented by the matrix multiplication T * R * T (where T and R are the basic translate / rotate matrices with the respective parameters).
However, what your code does is just creating T (because initially, the matrix is identity), overwriting some parts for the rotation, and finally overwriting the translation part again.
To fix your code, you need to implement a proper matrix multipilcation method, and actually use it whenever you want to apply a further transformation to the matrix. It might be helpful to create some methods for the basic transformation matrices.
However, this still looks like the usual row major vs column major matrix storage layout order to me.
Your layout of the mXY members suggest that you use mathematical convention where m12 would be second row, third column. Your store method then does put the matrix into a buffer with column major layout. Such a buffer could be directly used by legacy GL's matrix functions (like glLoadMatrix or glMultMatrix). It would also be the "standard" layout for matrix uniforms, where the transpose parameter is set to GL_FALSE.
However, looking at your translate method:
public Mat4f translate(float x, float y, float z) {
m30 = x;
m31 = y;
m32 = z;
return this;
}
This would set the translation vector to the last row, not the last column. (All the other functions also seem to use a transposed layout).
Now legacy GL uses the matrix * vector convention (as opposed to vector * matrix which D3D prefers). In that case, your matrices are transposed to what the GL expects. If you use shaders, it is up to you which multiplication order you use, though - but it must match the convention you are using for your matrices, and M * v == v^T * M^T.
The issue was indeed that I didn't take earlier transformations into consideration. I ended up not using matrix multiplication though. I copied the relevant parts from JOML, which you can reach at: https://github.com/JOML-CI/JOML.
I will edit the question to reflect what the problem was, and what the final state of the class is. Thanks JOML contributors, and Derhass for the help!
Related
I've been working on a project for some time and Needed something that could from a Vector3 representing rotation in the XYZ axis make Forward, Right and Up vectors. I was looking through a lot of stuff and after some time I figured out I had to implement Quaternions (I have my own Math Libary but this same thing happened with glm) and Here is the code for calculating the Forward Vector: (quaternion is the rotation Quaternion member in my class and Quaternion::Euler is a static function that returns a Quaternion from Euler Angles)
quaternion = Quaternion::Euler(rotation);
Vector3 ret = quaternion * Vector3(0.0f, 0.0f, 1.0f);
when the rotation is 0, 0, 0 the function returns 0, 0, 1 as it should, but if I try something like 0, 180, 0 it should return 0, 0, -1, but instead I get -8.74228e-08, 0, -1. After some investigation I figured out that the Quaternion::Euler function returns a Quaternion where the w part is messed up. In the case where the rotation is 0, 180, 0 the Quaternion the Quaternion::Euler function returns is 0, 1, 0, -4.37113883e-08 which is almost exactly half of the random number the Forward functions returns. Here is Quaternion::Euler:
float x = Radians(euler.x);
float y = Radians(euler.y);
float z = Radians(euler.z);
x = x / 2;
y = y / 2;
z = z / 2;
return Quaternion(cos(z) * cos(y) * sin(x) - sin(z) * sin(y) * cos(x), //X
cos(z) * sin(y) * cos(x) + sin(z) * cos(y) * sin(x), //Y
sin(z) * cos(y) * cos(x) - cos(z) * sin(y) * sin(x), //Z
cos(z) * cos(y) * cos(x) + sin(z) * sin(y) * sin(x));//W
and Honestly, I stole this function from an article of a guy that was making his own Math Engine, in his case this seemed to work. Here is the Quaternion Vector Multiplication function, that I "borrowed" from the Unity Implementation: (in this case it's inside the Quaternion struct so this is a pointer to the quaternion from the Quaternion Vector multiplication)
inline Vector3 operator*(const Vector3& other) {
float x = this->x * 2.0f;
float y = this->y * 2.0f;
float z = this->z * 2.0f;
float xx = this->x * x;
float yy = this->y * y;
float zz = this->z * z;
float xy = this->x * y;
float xz = this->x * z;
float yz = this->y * z;
float wx = this->w * x;
float wy = this->w * y;
float wz = this->w * z;
Vector3 ret;
ret.x = (1.0f - (yy + zz)) * other.x + (xy - wz) * other.y + (xz + wy) * other.z;
ret.y = (xy + wz) * other.x + (1.0f - (xx + zz)) * other.y + (yz - wx) * other.z;
ret.z = (xz - wy) * other.x + (yz + wx) * other.y + (1.0f - (xx + yy)) * other.z;
return ret;
}
Does anyone know what might be wrong ? I tried to do this with glm:
glm::quat quat(glm::vec3(glm::radians(rotation.x), glm::radians(rotation.y), glm::radians(rotation.z)));
glm::vec3 v = quat * glm::vec3(0.0f, 0.0f, 1.0f);
but it's the same thing, the vector is the same and the quaternion is the same too, I've been reading into things a lot about this and couldn't find a fix, always when I tried to search implementation for the Quaternio::Euler function it just came up with how to use a math library. It would be best if the solution wouldn't require me to use glm, because I have to use my own Math Library, but honestly I will try anything to at least understand what is wrong.
I need to rotate bones of skeleton, i have already the quaterinion corresponding for each joints; and i am confused when it comes on rotating.
Skeleton to move is my opengl scene i need to move.
My problem is that i can't rotate the joint; Can anyone Help
Bellow is my code
//i evaluate each joint to get the translation and rotation.
void Node::EvaluatePoi(std::vector<POI> pois, const Vector &par_pos,
const Quaternion &par_rot, Vector Node::*world_pos,std::vector<Arti> joints)
{ Vector poi=this->PoiVec ;
Quaternion rot;
if (pois.empty()){
this->*world_pos= this->rest_position ;//OFFSET
rot= this-> rest_rotation ;//identity
}else{
if(this->name=="Hips")
{
this->*world_pos = eval_instant_positionPOI(poi);
rot= this-> rest_rotation ;// do not rotate
}else if(this->name=="LeftUpLeg")
{
this->*world_pos = this->rest_position;// set to OFFSET
rot= this-> rest_rotation ;// do not rotate
}else if(this->name=="RightUpLeg")
{
this->*world_pos = this->rest_position;
rot= this-> rest_rotation ;
}
else
{
this->*world_pos= this->rest_position;
rot= eval_instant_rotationPOI(joints);
}
}
//Applying transformation on the global position with rot =qparent * qchild
(this->*world_pos).rotate(par_rot);
this->*world_pos += par_pos;
rot = par_rot * rot;
// draw joint's subhierarchy
for (int i = 0; i < n_children; i++)
child[i]->EvaluatePoi(pois, this->*world_pos, rot, world_pos,joints);
}
EDIT:
//here i get the local rotation of each joint, after that create quaternions equivalent to individual Euler rotations and then compose to one rotation
Vector x_vector(1.0, 0.0, 0.0),
y_vector(0.0, 1.0, 0.0),
z_vector(0.0, 0.0, 1.0);
Quaternion Node::eval_instant_rotationPOI( std::vector<Arti> joints)
{
Quaternion roto;//= new Quaternion();
Quaternion sample;
double t= 0.02;
Vector v;
Vector Euler(0,0,0);;
string x =this->name;
if(x== "Head"){
Euler=GetEulers(joints,JOINT_HEAD);
}else if(x== "Neck"){
Euler=GetEulers(joints,JOINT_NECK);
}
else if(x== "LeftUpArm"){
Euler=GetEulers(joints,JOINT_LEFT_SHOULDER);
}
else if(x== "RightUpArm"){
Euler=GetEulers(joints,JOINT_RIGHT_SHOULDER);
}
else if(x== "LeftLowArm"){
Euler=GetEulers(joints,JOINT_LEFT_ELBOW);
}
else if(x== "LeftHand"){
Euler=GetEulers(joints,JOINT_LEFT_HAND);
}
else if(x== "RightLowArm"){
Euler=GetEulers(joints,JOINT_RIGHT_ELBOW);
}
else if(x== "RightHand"){
Euler=GetEulers(joints,JOINT_RIGHT_HAND);
}
else if(x== "Hips"){
Euler=GetEulers(joints,JOINT_TORSO);
}
else if(x== "LeftUpLeg"){
Euler=GetEulers(joints,JOINT_LEFT_HIP);
}
else if(x== "RightUpLeg"){
Euler=GetEulers(joints,JOINT_RIGHT_HIP);
}
else if(x== "LeftLowLeg"){
Euler=GetEulers(joints,JOINT_LEFT_KNEE);
}
else if(x== "LeftFoot"){
Euler=GetEulers(joints,JOINT_LEFT_FOOT);
}
else if(x== "RightLowLeg"){
Euler=GetEulers(joints,JOINT_RIGHT_KNEE);
}
else if(x== "RightFoot"){
Euler=GetEulers(joints,JOINT_RIGHT_FOOT);
}
Quaternion qx(x_vector, (Euler.x ));
Quaternion qy(y_vector, (Euler.y ));
Quaternion qz(z_vector, (Euler.z ));
sample = qz * qy * qx;
roto= slerp(qTemp, sample, t);
qTemp=roto;
return roto ;
}
/*here i multiply the joint and its parent to get the Euler Angle ; is it necessary to convert to
Euler Angle?/
Vector Node::GetEulers(std::vector<Arti> joints, const int idx) {
// Get the quaternion of its parent.
Quaternion q_parent;
Quaternion q_current;
if (idx == JOINT_TORSO) {
q_parent.identity();
}
/////
{
q_parent = Quaternion(joints[parent_joint_map[idx]].quat.x,
joints[parent_joint_map[idx]].quat.y,
joints[parent_joint_map[idx]].quat.z,
joints[parent_joint_map[idx]].quat.w);
}
// Get the quaternion of the joint.
q_current = Quaternion(joints[idx].quat.x, joints[idx].quat.y,
joints[idx].quat.z, joints[idx].quat.w);
// Calculate the relative quaternion.
Quaternion q_delta = quat_left_multiply(q_current , quat_inverse(q_parent));
Vector angle = euler_from_quat(q_delta);
// cout<<this->name<<" "<<angle<<" ";
return angle;
}
Quaternion quat_left_multiply(Quaternion l, Quaternion r) {
Quaternion q = {r.w * l.x + r.x * l.w + r.y * l.z - r.z * l.y,
r.w * l.y + r.y * l.w + r.z * l.x - r.x * l.z,
r.w * l.z + r.z * l.w + r.x * l.y - r.y * l.x,
r.w * l.w - r.x * l.x - r.y * l.y - r.z * l.z};
return q;
}
Vector& Vector::rotate(const Quaternion& q)
{
Quaternion p(x, y, z, 0.0f);
Quaternion qc(q);
qc.conjugate();
Quaternion pp(q * p * qc);
x = pp.x;
y = pp.y;
z = pp.z;
return *this;
}
Rotating a quaternion is actually multiplying a quaternion by another. Given the quaternion qA representing the current rotation of an object and qB the quaternion representing the amount of rotation to apply (to add) to this object, the resulting new rotation of this object is computed as follow (pseudocode):
qA = qA * qB;
Alternatively, you can apply (add) this rotation in what is called "object" or "local" transformation space by swapping operands:
qA = qB * qA
Each joint should hold (usualy as class member) a quaternion representing its current rotation in local space. This is probably what you already done. If you want to apply a rotation to that joint, then you simply need multiply the joint quaternion, by another quaternion representing the amount of rotation to apply. A quaterion rotation method can be like this (pseudocode):
Joint::Rotate(const quaterion& amount, bool local)
{
if(local) {
this->rotation = amount * this->rotation;
} else {
this->rotation = this->rotation * amount;
}
this->rotation.normalize();
}
That is all you need for the rotation part, nothing else. After that, you will need to convert the joint quaternion to a rotation matrix, so to be combined with the other joint transformations (translation, scale, whatever). Here is one implementation of the quaternion to rotation matrix conversion (pseudocode):
Matrix3 QuaternionToMatrix(const quaternion& q)
{
float x2 = q.x + q.x;
float y2 = q.y + q.y;
float z2 = q.z + q.z;
float xx = q.x * x2;
float xy = q.x * y2;
float xz = q.x * z2;
float yy = q.y * y2;
float yz = q.y * z2;
float zz = q.z * z2;
float wx = q.w * x2;
float wy = q.w * y2;
float wz = q.w * z2;
Matrix3 m; //< 3x3 matrix
m[0] = (1.0f - (yy + zz));
m[1] = (xy - wz);
m[2] = (xz + wy);
m[3] = (xy + wz);
m[4] = (1.0f - (xx + zz));
m[5] = (yz - wx);
m[6] = (xz - wy);
m[7] = (yz + wx);
m[8] = (1.0f - (xx + yy));
return m;
}
What you may finally need is to input rotation using Euler angles instead of quaternion values. Indeed, Euler angles are easier to handle and understand when it come to apply a rotation in a human point of view. In this case, you'll need to convert the input Euler angles to a quaternion. Here is one possible implementation of Euler angle to quaternion conversion:
Quaternion EulerToQuaternion(float x, float y, float z)
{
float sx = sinf(x * -0.5f);
float cx = cosf(x * -0.5f);
float sy = sinf(y * -0.5f);
float cy = cosf(y * -0.5f);
float sz = sinf(z * -0.5f);
float cz = cosf(z * -0.5f);
Quaternion q;
q.x = sx * cy * cz + cx * sy * sz;
q.y = cx * sy * cz - sx * cy * sz;
q.z = cx * cy * sz + sx * sy * cz;
q.w = cx * cy * cz - sx * sy * sz;
return q;
}
I understand that both Euler and Quaternion rotation types have their own distinctive quirks, however the problem that I'm having is that (for example) when performing the following rotations to an object:
rotateX = 90.0
rotateY = 90.0
... Oh, hang on a minute... now the X and Z axis are basically the same!
See, what I want is to rotate a cube say 90 degrees X, 90 degrees Y and still have all axis points back in their original position as opposed of rotating locally.
Any code examples would be ideal - Here is the code I'm currently using:
_model = scale(_scale) *
translate(_position) *
( rotate(_rotation.data[0], 1.0f, 0.0f, 0.0f) *
rotate(_rotation.data[1], 0.0f, 1.0f, 0.0f) *
rotate(_rotation.data[2], 0.0f, 0.0f, 1.0f) );
I have a Math.h that calculates the rotations like so:
template <typename T>
static inline Tmat4<T> rotate(T angle, T x, T y, T z)
{
Tmat4<T> result;
const T x2 = x * x;
const T y2 = y * y;
const T z2 = z * z;
float rads = float(angle) * 0.0174532925f;
const float c = cosf(rads);
const float s = sinf(rads);
const float omc = 1.0f - c;
result[0] = Tvec4<T>(T(x2 * omc + c), T(y * x * omc + z * s), T(x * z * omc - y * s), T(0));
result[1] = Tvec4<T>(T(x * y * omc - z * s), T(y2 * omc + c), T(y * z * omc + x * s), T(0));
result[2] = Tvec4<T>(T(x * z * omc + y * s), T(y * z * omc - x * s), T(z2 * omc + c), T(0));
result[3] = Tvec4<T>(T(0), T(0), T(0), T(1));
return result;
}
I am trying to display a 360 panorama using an IMU for head tracking.
Yaw works correctly but the roll and pitch are reverse. I also notice that the pitch contains some roll (and maybe vice-versa).
I am receiving (W, X, Y, Z) coordinate from the IMU that I am storing in an array as X, Y, Z, W.
The next step is converting the quaternion to a rotation matrix. I have looked at many examples, and can't seem to find anything wrong with the following code:
static GLfloat rotation[16];
// Quaternion (x, y, z, w)
static void quaternionToRotation(float* quaternion)
{
// Normalize quaternion
float magnitude = sqrt(quaternion[0] * quaternion[0] +
quaternion[1] * quaternion[1] +
quaternion[2] * quaternion[2] +
quaternion[3] * quaternion[3]);
for (int i = 0; i < 4; ++i)
{
quaternion[i] /= magnitude;
}
double xx = quaternion[0] * quaternion[0], xy = quaternion[0] * quaternion[1],
xz = quaternion[0] * quaternion[2], xw = quaternion[0] * quaternion[3];
double yy = quaternion[1] * quaternion[1], yz = quaternion[1] * quaternion[2],
yw = quaternion[1] * quaternion[3];
double zz = quaternion[2] * quaternion[2], zw = quaternion[2] * quaternion[3];
// Column major order
rotation[0] = 1.0f - 2.0f * (yy + zz);
rotation[1] = 2.0f * (xy - zw);
rotation[2] = 2.0f * (xz + yw);
rotation[3] = 0;
rotation[4] = 2.0f * (xy + zw);
rotation[5] = 1.0f - 2.0f * (xx + zz);
rotation[6] = 2.0f * (yz - xw);
rotation[7] = 0;
rotation[8] = 2.0f * (xz - yw);
rotation[9] = 2.0f * (yz + xw);
rotation[10] = 1.0f - 2.0f * (xx + yy);
rotation[11] = 0;
rotation[12] = 0;
rotation[13] = 0;
rotation[14] = 0;
rotation[15] = 1;
}
The rotation matrix is then used in the draw call as such:
static void draw()
{
// Get IMU quaternion
float* quaternion = tracker.getTrackingData();
if (quaternion != NULL)
{
quaternionToRotation(quaternion);
}
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glPushMatrix();
// TODO: Multiply initialRotation quaternion with IMU quaternion
glMultMatrixf(initialRotation); // Initial rotation to point forward
glMultMatrixf(rotation); // Rotation based on IMU
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
gluSphere(quad, 0.1, 50, 50);
glBindTexture(GL_TEXTURE_2D, 0);
glPopMatrix();
glFlush();
glutSwapBuffers();
}
I tried to set all but one fields in the quaternion to 0, and I notice that they all work individually, except roll and pitch is swapped around. I tried swapping X and Y but this does not seem to help.
Any help would be really appreciated. Please let me know as well if you have any steps that can let me debug my issue. Thanks!
I am trying to map a texture to a circle using GL_POLYGON using this code:
void drawCircleOutline(Circle c, int textureindex)
{
float angle, radian, x, y; // values needed by drawCircleOutline
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textureLib[textureindex]);
glBegin(GL_POLYGON);
for (angle=0.0; angle<360.0; angle+=2.0)
{
radian = angle * (pi/180.0f);
x = (float)cos(radian) * c.r + c.pos.x;
y = (float)sin(radian) * c.r + c.pos.y;
glTexCoord2f(x, y);
glVertex2f(x, y);
}
glEnd();
glDisable(GL_TEXTURE_2D);
}
it looks like this when running.
And should look like this:
Try:
radian = angle * (pi/180.0f);
xcos = (float)cos(radian);
ysin = (float)sin(radian);
x = xcos * c.r + c.pos.x;
y = ysin * c.r + c.pos.y;
tx = xcos * 0.5 + 0.5;
ty = ysin * 0.5 + 0.5;
glTexCoord2f(tx, ty);
glVertex2f(x, y);