quaternion.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00027 #include "renderstack/matrix.hpp"
00028 #include "renderstack/quaternion.hpp"
00029
00030 namespace renderstack {
00031
00032 vec3 quaternion::hpb() const
00033 {
00034 float sqx = x * x;
00035 float sqy = y * y;
00036 float sqz = z * z;
00037
00038 float singularity_test = x * y + z * w;
00039 int north_pole_singularity = singularity_test > (0.5f - RS_EPSILON);
00040 int south_pole_singularity = singularity_test < -(0.5f - RS_EPSILON);
00041
00042 if(north_pole_singularity)
00043 {
00044 return vec3(
00045 -2.0f * atan2f(x, w),
00046 RS_HALF_PI,
00047 0.0f
00048 );
00049 }
00050
00051 if(south_pole_singularity)
00052 {
00053 return vec3(
00054 2.0f * atan2f(x, w),
00055 RS_HALF_PI,
00056 0
00057 );
00058 }
00059 return vec3(
00060 -atan2f(2.0f * y * w - x * z, 1.0f - 2.0f * (sqy - sqz)),
00061 asinf (2.0f * x * y + z * w),
00062 -atan2f(2.0f * x * w - y * z, 1.0f - 2.0f * (sqx - sqz))
00063 );
00064 }
00065
00066
00067 vec3 quaternion::view_axis() const
00068 {
00069 float x2 = 2.0f * x;
00070 float y2 = 2.0f * y;
00071 float z2 = 2.0f * z;
00072 float xx = x * x2;
00073 float xz = x * z2;
00074 float yy = y * y2;
00075 float yz = y * z2;
00076 float wx = w * x2;
00077 float wy = w * y2;
00078
00079 return vec3(
00080 xz + wy,
00081 yz - wx,
00082 1.0f - (xx + yy)
00083 );
00084 }
00085
00086
00087 vec3 quaternion::up_axis() const
00088 {
00089 float x2 = 2.0f * x;
00090 float y2 = 2.0f * y;
00091 float z2 = 2.0f * z;
00092 float xx = x * x2;
00093 float xy = x * y2;
00094 float yz = y * z2;
00095 float zz = y * z2;
00096 float wx = w * x2;
00097 float wz = w * z2;
00098
00099 return vec3(
00100 xy - wz,
00101 1.0f - (xx + zz),
00102 yz + wx
00103 );
00104 }
00105
00106
00107 vec3 quaternion::right_axis() const
00108 {
00109 float y2 = 2.0f * y;
00110 float z2 = 2.0f * z;
00111 float xy = x * y2;
00112 float xz = x * z2;
00113 float yy = y * y2;
00114 float zz = z * z2;
00115 float wy = w * y2;
00116 float wz = w * z2;
00117
00118 return vec3(
00119 1.0f - (yy + zz),
00120 xy + wz,
00121 xz - wy
00122 );
00123 }
00124
00125
00126
00127 quaternion::quaternion(matrix const &mat)
00128 {
00129
00130 float tr = mat.m[0][0] + mat.m[1][1] + mat.m[2][2];
00131
00132 if(tr > RS_EPSILON )
00133 {
00134
00135 float s = sqrtf(tr + 1.0f);
00136 w = 0.5f * s;
00137 s = 0.5f / s;
00138 x = (mat.m[1][2] - mat.m[2][1]) * s;
00139 y = (mat.m[2][0] - mat.m[0][2]) * s;
00140 z = (mat.m[0][1] - mat.m[1][0]) * s;
00141 }
00142 else
00143 {
00144
00145 float *q[3] = {&y, &z, &x};
00146 int const n_index[3] = {1, 2, 0};
00147 int i = 0;
00148 if(mat.m[1][1] > mat.m[i][i]) i = 1;
00149 if(mat.m[2][2] > mat.m[i][i]) i = 2;
00150 int j = n_index[i];
00151 int k = n_index[j];
00152
00153 float s = sqrtf(
00154 mat.m[i][i] - (mat.m[j][j] + mat.m[k][k]) + 1.0f
00155 );
00156 *q[i] = 0.5f * s;
00157 if(s != 0)
00158 {
00159 s = 0.5f / s;
00160 }
00161 *q[j] = (mat.m[i][j] + mat.m[j][i]) * s;
00162 *q[k] = (mat.m[i][k] + mat.m[k][i]) * s;
00163 w = (mat.m[j][k] + mat.m[k][j]) * s;
00164 }
00165 }
00166
00167 quaternion quaternion::operator*(quaternion const &q2) const
00168 {
00169 float E = (x + z) * (q2.x + q2.y);
00170 float F = (z - x) * (q2.x - q2.y);
00171 float G = (w + y) * (q2.w - q2.z);
00172 float H = (w - y) * (q2.w + q2.z);
00173 float A = F - E;
00174 float B = F + E;
00175 float GmH = G - H;
00176 float GpH = G + H;
00177
00178 return quaternion(
00179 (w + x) * (q2.w + q2.x) + 0.5f * (A - GpH),
00180 (w - x) * (q2.y + q2.z) + 0.5f * (B + GmH),
00181 (y + z) * (q2.w - q2.x) + 0.5f * (B - GmH),
00182 (z - y) * (q2.y - q2.z) + 0.5f * (A + GpH)
00183 );
00184 }
00185
00186 }
00187