# Vector rotation via Quaternion

This topic is 2352 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello,

I am using this webpage to build some of my methods for my game engine's quaternion class.

I am having trouble with the vector rotation via quaternion code. In the webpage cited above, this is what it looks like.

// Multiplying a quaternion q with a vector v applies the q-rotation to v
Vector3 Quaternion::operator* (const Vector3 &vec) const
{
Vector3 vn(vec);
vn.normalise();

Quaternion vecQuat, resQuat;
vecQuat.x = vn.x;
vecQuat.y = vn.y;
vecQuat.z = vn.z;
vecQuat.w = 0.0f;

resQuat = vecQuat * getConjugate();
resQuat = *this * resQuat;

return (Vector3(resQuat.x, resQuat.y, resQuat.z));
}

So I use it in my quaternion class but I get incorrect results.

This is what I do to test the method...

Vector3 pos = new Vector3(1.0f, 0.0f ,0.0f);

Quaternion q = new Quaternion(0.0f, 0.0f, 45f);

pos = q.Rotate(pos);

To my current perspective, this will give me <~-0.707, ~0.707, 0.0f>. But it doesn't, I get <-0.13529904, 0.3535534, -0.3744762>, which seems to me to be way off.

Here is my code for the quaternion-vector rotation method...

/**
* Multiplys a quaternion q with a vector v to apply the q-rotation to v
*/
public Vector3 Rotate (Vector3 vec)
{
vecnormal.Set(vec);
vecnormal.Normalize();
qVec.x = vecnormal.X;
qVec.y = vecnormal.Y;
qVec.z = vecnormal.Z;
qVec.w = 0.0f;

qConjugate.Set(this).Conjugate();

Quaternion qRes = qVec.Multiply(qConjugate);
qTmpThis.Set(this);
qRes = qTmpThis.Multiply(qRes);

vec.X = qRes.x; vec.Y = qRes.y; vec.Z = qRes.z;
return vec;
}

My code is in Java, so that is why it looks different. I apprecaite any help or ideas!!

Thanks! Edited by Michael Wojcik

##### Share on other sites
What does the quaternion constructor with three arguments do?

##### Share on other sites
Quaternion q = new Quaternion(0.0f, 0.0f, 45f);

Initializes the quaternion in euler angles which calls this method

public void FromEulerAngles(float x, float y, float z)
{

float cyaw, cpitch, croll, syaw, spitch, sroll;
float cyawcpitch, syawspitch, cyawspitch, syawcpitch;

cyaw = MathHelper.Cos(0.5f * yaw);
cpitch = MathHelper.Cos(0.5f * pitch);
croll = MathHelper.Cos(0.5f * roll);
syaw = MathHelper.Sin(0.5f * yaw);
spitch = MathHelper.Sin(0.5f * pitch);
sroll = MathHelper.Sin(0.5f * roll);

cyawcpitch = cyaw*cpitch;
syawspitch = syaw*spitch;
cyawspitch = cyaw*spitch;
syawcpitch = syaw*cpitch;

this.w = cyawcpitch * croll + syawspitch * sroll;
this.x = cyawspitch * croll + syawcpitch * sroll;
this.y = syawcpitch * croll - cyawspitch * sroll;
this.z = cyawcpitch * sroll - syawspitch * croll;
}

The Quaternion.Set sets to the calling quaternion's members, the x,y,z,w from that of the quaternion passed into set.

Here's Quaternion.Set
public Quaternion Set(Quaternion rhs)
{
this.x = rhs.x;
this.y = rhs.y;
this.z = rhs.z;
this.w = rhs.w;
return this;
}

Heres my Quaternion.Multiply, just in case
public Quaternion Multiply(Quaternion qLocal)
{
w = ((w * qLocal.w) - (x * qLocal.x) - (y * qLocal.y) - (z * qLocal.z));
x = ((w * qLocal.x) + (x * qLocal.w) + (y * qLocal.z) - (z * qLocal.y));
y = ((w * qLocal.y) + (y * qLocal.w) + (z * qLocal.x) - (x * qLocal.z));
z = ((w * qLocal.z) + (z * qLocal.w) + (x * qLocal.y) - (y * qLocal.x));

normalRegenerationCount++;
return this;
}
Edited by Michael Wojcik

##### Share on other sites
Use a debugger to see where things are going wrong. I built a quaternion using you code to convert Euler angles to a quaternion and then tested the same rotation of (1,0,0) using angles (0,0,45), but my results were correct:
#include <iostream>
#include <boost/math/quaternion.hpp>
#include <cmath>

typedef boost::math::quaternion<double> quaternion;

quaternion euler_to_quaternion(double x, double y, double z) {
double const degrees = std::atan(1.0)/45.0;

float roll = z * degrees;
float pitch = x * degrees;
float yaw = y * degrees;

float cyaw, cpitch, croll, syaw, spitch, sroll;
float cyawcpitch, syawspitch, cyawspitch, syawcpitch;

cyaw = std::cos(0.5f * yaw);
cpitch = std::cos(0.5f * pitch);
croll = std::cos(0.5f * roll);
syaw = std::sin(0.5f * yaw);
spitch = std::sin(0.5f * pitch);
sroll = std::sin(0.5f * roll);

cyawcpitch = cyaw*cpitch;
syawspitch = syaw*spitch;
cyawspitch = cyaw*spitch;
syawcpitch = syaw*cpitch;

return quaternion(cyawcpitch * croll + syawspitch * sroll,
cyawspitch * croll + syawcpitch * sroll,
syawcpitch * croll - cyawspitch * sroll,
cyawcpitch * sroll - syawspitch * croll);
}

struct Vector3D {
double x, y, z;

Vector3D(double x, double y, double z) : x(x), y(y), z(z) {
}
};

Vector3D apply(quaternion const &q, Vector3D const &v) {
quaternion qv(0.0, v.x, v.y, v.z);
quaternion result = q * qv * conj(q);
return Vector3D(result.R_component_2(),
result.R_component_3(),
result.R_component_4());
}

std::ostream &operator<<(std::ostream &os, Vector3D const &v) {
return os << '(' << v.x << ',' << v.y << ',' << v.z << ')';
}

int main() {
quaternion q = euler_to_quaternion(0.0, 0.0, 45.0);
Vector3D v(1.0, 0.0, 0.0);
std::cout << q << " applied to " << v << " is " << apply(q,v) << '\n';
}

The output is this:
(0.92388,0,0,0.382683) applied to (1,0,0) is (0.707107,0.707107,0)

##### Share on other sites

Heres my Quaternion.Multiply, just in case
public Quaternion Multiply(Quaternion qLocal)
{
w = ((w * qLocal.w) - (x * qLocal.x) - (y * qLocal.y) - (z * qLocal.z));
x = ((w * qLocal.x) + (x * qLocal.w) + (y * qLocal.z) - (z * qLocal.y));
y = ((w * qLocal.y) + (y * qLocal.w) + (z * qLocal.x) - (x * qLocal.z));
z = ((w * qLocal.z) + (z * qLocal.w) + (x * qLocal.y) - (y * qLocal.x));

normalRegenerationCount++;
return this;
}

Oh, that's all messed up. You are using the same w,x,y,z variables for input and output, and as you do the computations you forget the old values, which you still need for the lines following. You are probably better off implementing a function that takes two quaternions and returns a fresh one, instead of having one of the quaternions be both source and destination.

##### Share on other sites
Cool! Thats was indeed the issue! You saved me alot of time, thanks! I have another question regarding the result of quaternion - vector rotation. I noticed that If I were to pass <5.0, 0.0,0.0> I get a normal (0.707107,0.707107,0) as If I passed in <1.0, 0.0,0.0>.

Does quaternion rotation with vector only work with vector normals? Or might I have messed something else up in my class?

##### Share on other sites
I don't understand your last question. You pass <5,0, 0.0, 0.0> to what?

##### Share on other sites
To the method to rotate the vector by a quaternion.

/**
* Multiplys a quaternion q with a vector v to apply the q-rotation to v
*/
public Vector3 Rotate (Vector3 vec)
{
vecnormal.Set(vec);
vecnormal.Normalize();
qVec.x = vecnormal.X;
qVec.y = vecnormal.Y;
qVec.z = vecnormal.Z;
qVec.w = 0.0f;

qConjugate.Set(this).Conjugate();

Quaternion qRes = qVec.Multiply(qConjugate);
qTmpThis.Set(this);
qRes = qTmpThis.Multiply(qRes);

vec.X = qRes.x; vec.Y = qRes.y; vec.Z = qRes.z;
return vec;
}

The result is always normal, no matter the magnitude of the input vector. Is this correct in the context of vector rotation via a quaternion? I was expecting the vector to be returned as a coordinate. I could ofcourse, could mutiply the result normal by the magnitude of the input vector. But I want to be sure if by definition, q * p * q-1 returns a rotated normal, or coordinate. Edited by Michael Wojcik

##### Share on other sites
Well, look at this line in your code:
vecnormal.Normalize();

What do you expect? ;)

##### Share on other sites
True! Lol, Thanks for pointing that out, I should have noticed that normalization was not critical to the rotation calculation. Thanks for all your help!

1. 1
2. 2
Rutin
19
3. 3
khawk
18
4. 4
5. 5

• 9
• 12
• 16
• 26
• 10
• ### Forum Statistics

• Total Topics
633769
• Total Posts
3013759
×