We closed this forum 18 June 2010. It has served us well since 2005 as the ALPHA forum did before it from 2002 to 2005. New discussions are ongoing at the new URL http://forum.processing.org. You'll need to sign up and get a new user account. We're sorry about that inconvenience, but we think it's better in the long run. The content on this forum will remain online.
IndexProgramming Questions & HelpOpenGL and 3D Libraries › Quaternions for Dummies
Page Index Toggle Pages: 1
Quaternions for Dummies (Read 2961 times)
Quaternions for Dummies
Jul 17th, 2006, 4:59pm
 
I'm trying to learn Quaternions for an implementation of L-Systems in 3D. I can't dumb it down using the pre-built Processing functions because I want to take the code and port it into Python as a module for Blender.

I have looked at the following resources and I think I understand axis and angle (self-taught in maths unfortunately) but I don't know how to effect a rotation, I'm not sure what my first and second Quaternions should be.  Each tutorial confuses me at the finish line by stating the solution as an equation I already don't understand.

http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/index.htm#sample

http://www.cprogramming.com/tutorial/3d/quaternions.html

The classes are from Ariel's ArcBall, with some of the math from the cprogramming link.

I would like to simply walk +100 pixels along the x axis and then rotate HALF_PI through the x axis (like being moved on the end of a stick). I would consider this a "Hello Quaternions!" I have posed this question with the classes below in the hope that someone might be able to show me how to apply them.
Code:

Vec3 here, there, axis;
float angle;
Quat rot;
void setup(){
size(400, 400, P3D);
here = new Vec3(0, 0, 0);
there = new Vec3(100, 0, 0);
axis = new Vec3(100, 0, 0);
angle = HALF_PI;
rot = new Quat();
}
void draw(){
translate(200, 200);
pushMatrix();
translate(here.x, here.y, here.z);
box(30, 30, 30);
popMatrix();
pushMatrix();
translate(there.x, there.y, there.z);
box(30, 30, 30);
popMatrix();
}

static class Vec3{
float x, y, z;
Vec3(){
}
Vec3(float x, float y, float z){
this.x = x;
this.y = y;
this.z = z;
}
void normalize(){
float length = length();
x /= length;
y /= length;
z /= length;
}
float length(){
return (float) Math.sqrt(x * x + y * y + z * z);
}
static Vec3 cross(Vec3 v1, Vec3 v2){
Vec3 res = new Vec3();
res.x = v1.y * v2.z - v1.z * v2.y;
res.y = v1.z * v2.x - v1.x * v2.z;
res.z = v1.x * v2.y - v1.y * v2.x;
return res;
}
static float dot(Vec3 v1, Vec3 v2){
return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
}
static Vec3 mul(Vec3 v, float d){
Vec3 res = new Vec3();
res.x = v.x * d;
res.y = v.y * d;
res.z = v.z * d;
return res;
}
void sub(Vec3 v1, Vec3 v2){
x = v1.x - v2.x;
y = v1.y - v2.y;
z = v1.z - v2.z;
}
}

static class Quat{
float w, x, y, z;
Quat(){
reset();
}
Quat(float w, float x, float y, float z){
this.w = w;
this.x = x;
this.y = y;
this.z = z;
}
void reset(){
w = 1.0f;
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
void set(float w, Vec3 v){
this.w = w;
x = v.x;
y = v.y;
z = v.z;
}
void set(Quat q){
w = q.w;
x = q.x;
y = q.y;
z = q.z;
}
static Quat mul(Quat q1, Quat q2){
Quat res = new Quat();
res.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z;
res.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y;
res.y = q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z;
res.z = q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x;
return res;
}
float[] getValue(){
// transforming this quat into an angle and an axis vector...
float[] res = new float[4];
float sa = (float) Math.sqrt(1.0f - w * w);
if (sa < EPSILON){
sa = 1.0f;
}
res[0] = (float) Math.acos(w) * 2.0f;
res[1] = x / sa;
res[2] = y / sa;
res[3] = z / sa;
return res;
}
}
Quat localRotation(float angle, Vec3 axis){
return new Quat(
cos(angle/2),
axis.x * sin(angle/2),
axis.y * sin(angle/2),
axis.z * sin(angle/2));
}
float [] quatTo2Matrix(Quat q){
float [] m = new float[16];
m[0] = 1 - 2 * sq(q.y) - 2 * sq(q.z);
m[1] = 2 * q.x * q.y - 2 * q.w * q.z;
m[2] = 2 * q.x * q.z + 2 * q.w * q.y;
m[3] = 0;
m[4] = 2 * q.x * q.y + 2 * q.w * q.z;
m[5] = 1 - 2 * sq(x) - 2 * sq(z);
m[6] = 2 * q.y * q.z - 2 * q.w * q.z;
m[7] = 0;
m[8] = 2 * q.x * q.z - 2 * q.w * q.y;
m[9] = 2 * q.y * q.z - 2 * q.w * q.z;
m[10] = 1 - 2 * sq(x) - 2 * sq(y);
m[11] = 0;
m[12] = 0;
m[13] = 0;
m[14] = 0;
m[15] = 1;
}
Re: Quaternions for Dummies
Reply #1 - Jul 19th, 2006, 3:24pm
 
I've discovered the above code won't help without a load of extra code for a transformation matrix. I decided to search for info about these and got a much better understanding of what is going on. The folowing link is excellent:

http://www.sacredsoftware.net/tutorials/Matrices/Matrices.xhtml

I wrote out a Matrix class with transformation and rotation functions.

My demo applet seems not to work though.

Rotation only seems to work after translation which I can understand, but rotation seems to send it all over the shop. What's going on?

http://www.robotacid.com/PBeta/quaternions/
Re: Quaternions for Dummies
Reply #2 - Jul 22nd, 2006, 3:15am
 
Can't say I can help you much, I'm on the same boat as you Smiley

So, I will cheerlead you on. This is something I wish to learn as well.
Re: Quaternions for Dummies
Reply #3 - Aug 4th, 2006, 3:46am
 
It seems the problem is that your quatTo2Matrix function is based on a row-major matrix array while your Matrix class is using column-major.

Choose one of the two standards, or if you need to translate between the two implement a matrix-transform function (reflection along the diagonal).
Re: Quaternions for Dummies
Reply #4 - Aug 7th, 2006, 1:09pm
 
Ah, thanks. This is the trouble with developing code from two different websites. I'll have a play with that when I get home.

I started looking at the Matrix class that Processing uses. I noticed that transformation seems to work differently to the OpenGL site's method. It's a += of some multiplied matrix elements rather than add to the transform and then multiply by it.

The big trouble with my transformations is that each one multiplies on the last. Whereas in Processing, translate() does not apply any scale. I'm clearly doing it wrong.

Does anybody know what exactly I'm screwing up on?
Re: Quaternions for Dummies
Reply #5 - Aug 8th, 2006, 3:07am
 
The website's code is written for clarity, since they constructed a translation matrix and then pre-multiplied the existing matrix to it. Processing's PMatrix code seems to have been written to optimize speed, so if you multiply out:

|m00 m01 m02 m03|     |1 0 0 x|
|m10 m11 m12 m13|  x  |0 1 0 y|
|m20 m21 m22 m23|     |0 0 1 z|
|m30 m31 m32 m33|     |0 0 0 1|

You will only really need to change m03, m13, m23, m33 and the identity matrix part of translation keeps the other elements invariant. Reducing the function to Processing's version.

(your questions help me solidify my understanding of all this, so thanks!)
Page Index Toggle Pages: 1