Matrix.java revision 0a088f5d4681fd2da6f610de157bf905df787bf7
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.opengl; 18 19/** 20 * Matrix math utilities. These methods operate on OpenGL ES format 21 * matrices and vectors stored in float arrays. 22 * 23 * Matrices are 4 x 4 column-vector matrices stored in column-major 24 * order: 25 * <pre> 26 * m[offset + 0] m[offset + 4] m[offset + 8] m[offset + 12] 27 * m[offset + 1] m[offset + 5] m[offset + 9] m[offset + 13] 28 * m[offset + 2] m[offset + 6] m[offset + 10] m[offset + 14] 29 * m[offset + 3] m[offset + 7] m[offset + 11] m[offset + 15] 30 * </pre> 31 * 32 * Vectors are 4 row x 1 column column-vectors stored in order: 33 * <pre> 34 * v[offset + 0] 35 * v[offset + 1] 36 * v[offset + 2] 37 * v[offset + 3] 38 * </pre> 39 * 40 */ 41public class Matrix { 42 43 /** Temporary memory for operations that need temporary matrix data. */ 44 private final static float[] sTemp = new float[32]; 45 46 /** 47 * Multiply two 4x4 matrices together and store the result in a third 4x4 48 * matrix. In matrix notation: result = lhs x rhs. Due to the way 49 * matrix multiplication works, the result matrix will have the same 50 * effect as first multiplying by the rhs matrix, then multiplying by 51 * the lhs matrix. This is the opposite of what you might expect. 52 * 53 * The same float array may be passed for result, lhs, and/or rhs. However, 54 * the result element values are undefined if the result elements overlap 55 * either the lhs or rhs elements. 56 * 57 * @param result The float array that holds the result. 58 * @param resultOffset The offset into the result array where the result is 59 * stored. 60 * @param lhs The float array that holds the left-hand-side matrix. 61 * @param lhsOffset The offset into the lhs array where the lhs is stored 62 * @param rhs The float array that holds the right-hand-side matrix. 63 * @param rhsOffset The offset into the rhs array where the rhs is stored. 64 * 65 * @throws IllegalArgumentException if result, lhs, or rhs are null, or if 66 * resultOffset + 16 > result.length or lhsOffset + 16 > lhs.length or 67 * rhsOffset + 16 > rhs.length. 68 */ 69 public static native void multiplyMM(float[] result, int resultOffset, 70 float[] lhs, int lhsOffset, float[] rhs, int rhsOffset); 71 72 /** 73 * Multiply a 4 element vector by a 4x4 matrix and store the result in a 4 74 * element column vector. In matrix notation: result = lhs x rhs 75 * 76 * The same float array may be passed for resultVec, lhsMat, and/or rhsVec. 77 * However, the resultVec element values are undefined if the resultVec 78 * elements overlap either the lhsMat or rhsVec elements. 79 * 80 * @param resultVec The float array that holds the result vector. 81 * @param resultVecOffset The offset into the result array where the result 82 * vector is stored. 83 * @param lhsMat The float array that holds the left-hand-side matrix. 84 * @param lhsMatOffset The offset into the lhs array where the lhs is stored 85 * @param rhsVec The float array that holds the right-hand-side vector. 86 * @param rhsVecOffset The offset into the rhs vector where the rhs vector 87 * is stored. 88 * 89 * @throws IllegalArgumentException if resultVec, lhsMat, 90 * or rhsVec are null, or if resultVecOffset + 4 > resultVec.length 91 * or lhsMatOffset + 16 > lhsMat.length or 92 * rhsVecOffset + 4 > rhsVec.length. 93 */ 94 public static native void multiplyMV(float[] resultVec, 95 int resultVecOffset, float[] lhsMat, int lhsMatOffset, 96 float[] rhsVec, int rhsVecOffset); 97 98 /** 99 * Transposes a 4 x 4 matrix. 100 * 101 * @param mTrans the array that holds the output inverted matrix 102 * @param mTransOffset an offset into mInv where the inverted matrix is 103 * stored. 104 * @param m the input array 105 * @param mOffset an offset into m where the matrix is stored. 106 */ 107 public static void transposeM(float[] mTrans, int mTransOffset, float[] m, 108 int mOffset) { 109 for (int i = 0; i < 4; i++) { 110 int mBase = i * 4 + mOffset; 111 mTrans[i + mTransOffset] = m[mBase]; 112 mTrans[i + 4 + mTransOffset] = m[mBase + 1]; 113 mTrans[i + 8 + mTransOffset] = m[mBase + 2]; 114 mTrans[i + 12 + mTransOffset] = m[mBase + 3]; 115 } 116 } 117 118 /** 119 * Inverts a 4 x 4 matrix. 120 * 121 * @param mInv the array that holds the output inverted matrix 122 * @param mInvOffset an offset into mInv where the inverted matrix is 123 * stored. 124 * @param m the input array 125 * @param mOffset an offset into m where the matrix is stored. 126 * @return true if the matrix could be inverted, false if it could not. 127 */ 128 public static boolean invertM(float[] mInv, int mInvOffset, float[] m, 129 int mOffset) { 130 // Invert a 4 x 4 matrix using Cramer's Rule 131 132 // transpose matrix 133 final float src0 = m[mOffset + 0]; 134 final float src4 = m[mOffset + 1]; 135 final float src8 = m[mOffset + 2]; 136 final float src12 = m[mOffset + 3]; 137 138 final float src1 = m[mOffset + 4]; 139 final float src5 = m[mOffset + 5]; 140 final float src9 = m[mOffset + 6]; 141 final float src13 = m[mOffset + 7]; 142 143 final float src2 = m[mOffset + 8]; 144 final float src6 = m[mOffset + 9]; 145 final float src10 = m[mOffset + 10]; 146 final float src14 = m[mOffset + 11]; 147 148 final float src3 = m[mOffset + 12]; 149 final float src7 = m[mOffset + 13]; 150 final float src11 = m[mOffset + 14]; 151 final float src15 = m[mOffset + 15]; 152 153 // calculate pairs for first 8 elements (cofactors) 154 final float atmp0 = src10 * src15; 155 final float atmp1 = src11 * src14; 156 final float atmp2 = src9 * src15; 157 final float atmp3 = src11 * src13; 158 final float atmp4 = src9 * src14; 159 final float atmp5 = src10 * src13; 160 final float atmp6 = src8 * src15; 161 final float atmp7 = src11 * src12; 162 final float atmp8 = src8 * src14; 163 final float atmp9 = src10 * src12; 164 final float atmp10 = src8 * src13; 165 final float atmp11 = src9 * src12; 166 167 // calculate first 8 elements (cofactors) 168 final float dst0 = (atmp0 * src5 + atmp3 * src6 + atmp4 * src7) 169 - (atmp1 * src5 + atmp2 * src6 + atmp5 * src7); 170 final float dst1 = (atmp1 * src4 + atmp6 * src6 + atmp9 * src7) 171 - (atmp0 * src4 + atmp7 * src6 + atmp8 * src7); 172 final float dst2 = (atmp2 * src4 + atmp7 * src5 + atmp10 * src7) 173 - (atmp3 * src4 + atmp6 * src5 + atmp11 * src7); 174 final float dst3 = (atmp5 * src4 + atmp8 * src5 + atmp11 * src6) 175 - (atmp4 * src4 + atmp9 * src5 + atmp10 * src6); 176 final float dst4 = (atmp1 * src1 + atmp2 * src2 + atmp5 * src3) 177 - (atmp0 * src1 + atmp3 * src2 + atmp4 * src3); 178 final float dst5 = (atmp0 * src0 + atmp7 * src2 + atmp8 * src3) 179 - (atmp1 * src0 + atmp6 * src2 + atmp9 * src3); 180 final float dst6 = (atmp3 * src0 + atmp6 * src1 + atmp11 * src3) 181 - (atmp2 * src0 + atmp7 * src1 + atmp10 * src3); 182 final float dst7 = (atmp4 * src0 + atmp9 * src1 + atmp10 * src2) 183 - (atmp5 * src0 + atmp8 * src1 + atmp11 * src2); 184 185 // calculate pairs for second 8 elements (cofactors) 186 final float btmp0 = src2 * src7; 187 final float btmp1 = src3 * src6; 188 final float btmp2 = src1 * src7; 189 final float btmp3 = src3 * src5; 190 final float btmp4 = src1 * src6; 191 final float btmp5 = src2 * src5; 192 final float btmp6 = src0 * src7; 193 final float btmp7 = src3 * src4; 194 final float btmp8 = src0 * src6; 195 final float btmp9 = src2 * src4; 196 final float btmp10 = src0 * src5; 197 final float btmp11 = src1 * src4; 198 199 // calculate second 8 elements (cofactors) 200 final float dst8 = (btmp0 * src13 + btmp3 * src14 + btmp4 * src15) 201 - (btmp1 * src13 + btmp2 * src14 + btmp5 * src15); 202 final float dst9 = (btmp1 * src12 + btmp6 * src14 + btmp9 * src15) 203 - (btmp0 * src12 + btmp7 * src14 + btmp8 * src15); 204 final float dst10 = (btmp2 * src12 + btmp7 * src13 + btmp10 * src15) 205 - (btmp3 * src12 + btmp6 * src13 + btmp11 * src15); 206 final float dst11 = (btmp5 * src12 + btmp8 * src13 + btmp11 * src14) 207 - (btmp4 * src12 + btmp9 * src13 + btmp10 * src14); 208 final float dst12 = (btmp2 * src10 + btmp5 * src11 + btmp1 * src9 ) 209 - (btmp4 * src11 + btmp0 * src9 + btmp3 * src10); 210 final float dst13 = (btmp8 * src11 + btmp0 * src8 + btmp7 * src10) 211 - (btmp6 * src10 + btmp9 * src11 + btmp1 * src8 ); 212 final float dst14 = (btmp6 * src9 + btmp11 * src11 + btmp3 * src8 ) 213 - (btmp10 * src11 + btmp2 * src8 + btmp7 * src9 ); 214 final float dst15 = (btmp10 * src10 + btmp4 * src8 + btmp9 * src9 ) 215 - (btmp8 * src9 + btmp11 * src10 + btmp5 * src8 ); 216 217 // calculate determinant 218 final float det = 219 src0 * dst0 + src1 * dst1 + src2 * dst2 + src3 * dst3; 220 221 if (det == 0.0f) { 222 return false; 223 } 224 225 // calculate matrix inverse 226 final float invdet = 1.0f / det; 227 mInv[ mInvOffset] = dst0 * invdet; 228 mInv[ 1 + mInvOffset] = dst1 * invdet; 229 mInv[ 2 + mInvOffset] = dst2 * invdet; 230 mInv[ 3 + mInvOffset] = dst3 * invdet; 231 232 mInv[ 4 + mInvOffset] = dst4 * invdet; 233 mInv[ 5 + mInvOffset] = dst5 * invdet; 234 mInv[ 6 + mInvOffset] = dst6 * invdet; 235 mInv[ 7 + mInvOffset] = dst7 * invdet; 236 237 mInv[ 8 + mInvOffset] = dst8 * invdet; 238 mInv[ 9 + mInvOffset] = dst9 * invdet; 239 mInv[10 + mInvOffset] = dst10 * invdet; 240 mInv[11 + mInvOffset] = dst11 * invdet; 241 242 mInv[12 + mInvOffset] = dst12 * invdet; 243 mInv[13 + mInvOffset] = dst13 * invdet; 244 mInv[14 + mInvOffset] = dst14 * invdet; 245 mInv[15 + mInvOffset] = dst15 * invdet; 246 247 return true; 248 } 249 250 /** 251 * Computes an orthographic projection matrix. 252 * 253 * @param m returns the result 254 * @param mOffset 255 * @param left 256 * @param right 257 * @param bottom 258 * @param top 259 * @param near 260 * @param far 261 */ 262 public static void orthoM(float[] m, int mOffset, 263 float left, float right, float bottom, float top, 264 float near, float far) { 265 if (left == right) { 266 throw new IllegalArgumentException("left == right"); 267 } 268 if (bottom == top) { 269 throw new IllegalArgumentException("bottom == top"); 270 } 271 if (near == far) { 272 throw new IllegalArgumentException("near == far"); 273 } 274 275 final float r_width = 1.0f / (right - left); 276 final float r_height = 1.0f / (top - bottom); 277 final float r_depth = 1.0f / (far - near); 278 final float x = 2.0f * (r_width); 279 final float y = 2.0f * (r_height); 280 final float z = -2.0f * (r_depth); 281 final float tx = -(right + left) * r_width; 282 final float ty = -(top + bottom) * r_height; 283 final float tz = -(far + near) * r_depth; 284 m[mOffset + 0] = x; 285 m[mOffset + 5] = y; 286 m[mOffset +10] = z; 287 m[mOffset +12] = tx; 288 m[mOffset +13] = ty; 289 m[mOffset +14] = tz; 290 m[mOffset +15] = 1.0f; 291 m[mOffset + 1] = 0.0f; 292 m[mOffset + 2] = 0.0f; 293 m[mOffset + 3] = 0.0f; 294 m[mOffset + 4] = 0.0f; 295 m[mOffset + 6] = 0.0f; 296 m[mOffset + 7] = 0.0f; 297 m[mOffset + 8] = 0.0f; 298 m[mOffset + 9] = 0.0f; 299 m[mOffset + 11] = 0.0f; 300 } 301 302 303 /** 304 * Define a projection matrix in terms of six clip planes 305 * @param m the float array that holds the perspective matrix 306 * @param offset the offset into float array m where the perspective 307 * matrix data is written 308 * @param left 309 * @param right 310 * @param bottom 311 * @param top 312 * @param near 313 * @param far 314 */ 315 public static void frustumM(float[] m, int offset, 316 float left, float right, float bottom, float top, 317 float near, float far) { 318 if (left == right) { 319 throw new IllegalArgumentException("left == right"); 320 } 321 if (top == bottom) { 322 throw new IllegalArgumentException("top == bottom"); 323 } 324 if (near == far) { 325 throw new IllegalArgumentException("near == far"); 326 } 327 if (near <= 0.0f) { 328 throw new IllegalArgumentException("near <= 0.0f"); 329 } 330 if (far <= 0.0f) { 331 throw new IllegalArgumentException("far <= 0.0f"); 332 } 333 final float r_width = 1.0f / (right - left); 334 final float r_height = 1.0f / (top - bottom); 335 final float r_depth = 1.0f / (near - far); 336 final float x = 2.0f * (near * r_width); 337 final float y = 2.0f * (near * r_height); 338 final float A = (right + left) * r_width; 339 final float B = (top + bottom) * r_height; 340 final float C = -(far + near) * r_depth; 341 final float D = -2.0f * (far * near * r_depth); 342 m[offset + 0] = x; 343 m[offset + 5] = y; 344 m[offset + 8] = A; 345 m[offset + 9] = B; 346 m[offset + 10] = C; 347 m[offset + 14] = D; 348 m[offset + 11] = -1.0f; 349 m[offset + 1] = 0.0f; 350 m[offset + 2] = 0.0f; 351 m[offset + 3] = 0.0f; 352 m[offset + 4] = 0.0f; 353 m[offset + 6] = 0.0f; 354 m[offset + 7] = 0.0f; 355 m[offset + 12] = 0.0f; 356 m[offset + 13] = 0.0f; 357 m[offset + 15] = 0.0f; 358 } 359 360 /** 361 * Define a projection matrix in terms of a field of view angle, an 362 * aspect ratio, and z clip planes 363 * @param m the float array that holds the perspective matrix 364 * @param offset the offset into float array m where the perspective 365 * matrix data is written 366 * @param fovy field of view in y direction, in degrees 367 * @param aspect width to height aspect ratio of the viewport 368 * @param zNear 369 * @param zFar 370 */ 371 public static void perspectiveM(float[] m, int offset, 372 float fovy, float aspect, float zNear, float zFar) { 373 float f = 1.0f / (float) Math.tan(fovy * (Math.PI / 360.0)); 374 float rangeReciprocal = 1.0f / (zNear - zFar); 375 376 m[offset + 0] = f / aspect; 377 m[offset + 1] = 0.0f; 378 m[offset + 2] = 0.0f; 379 m[offset + 3] = 0.0f; 380 381 m[offset + 4] = 0.0f; 382 m[offset + 5] = f; 383 m[offset + 6] = 0.0f; 384 m[offset + 7] = 0.0f; 385 386 m[offset + 8] = 0.0f; 387 m[offset + 9] = 0.0f; 388 m[offset + 10] = (zFar + zNear) * rangeReciprocal; 389 m[offset + 11] = -1.0f; 390 391 m[offset + 12] = 0.0f; 392 m[offset + 13] = 0.0f; 393 m[offset + 14] = 2.0f * zFar * zNear * rangeReciprocal; 394 m[offset + 15] = 0.0f; 395 } 396 397 /** 398 * Computes the length of a vector 399 * 400 * @param x x coordinate of a vector 401 * @param y y coordinate of a vector 402 * @param z z coordinate of a vector 403 * @return the length of a vector 404 */ 405 public static float length(float x, float y, float z) { 406 return (float) Math.sqrt(x * x + y * y + z * z); 407 } 408 409 /** 410 * Sets matrix m to the identity matrix. 411 * @param sm returns the result 412 * @param smOffset index into sm where the result matrix starts 413 */ 414 public static void setIdentityM(float[] sm, int smOffset) { 415 for (int i=0 ; i<16 ; i++) { 416 sm[smOffset + i] = 0; 417 } 418 for(int i = 0; i < 16; i += 5) { 419 sm[smOffset + i] = 1.0f; 420 } 421 } 422 423 /** 424 * Scales matrix m by x, y, and z, putting the result in sm 425 * @param sm returns the result 426 * @param smOffset index into sm where the result matrix starts 427 * @param m source matrix 428 * @param mOffset index into m where the source matrix starts 429 * @param x scale factor x 430 * @param y scale factor y 431 * @param z scale factor z 432 */ 433 public static void scaleM(float[] sm, int smOffset, 434 float[] m, int mOffset, 435 float x, float y, float z) { 436 for (int i=0 ; i<4 ; i++) { 437 int smi = smOffset + i; 438 int mi = mOffset + i; 439 sm[ smi] = m[ mi] * x; 440 sm[ 4 + smi] = m[ 4 + mi] * y; 441 sm[ 8 + smi] = m[ 8 + mi] * z; 442 sm[12 + smi] = m[12 + mi]; 443 } 444 } 445 446 /** 447 * Scales matrix m in place by sx, sy, and sz 448 * @param m matrix to scale 449 * @param mOffset index into m where the matrix starts 450 * @param x scale factor x 451 * @param y scale factor y 452 * @param z scale factor z 453 */ 454 public static void scaleM(float[] m, int mOffset, 455 float x, float y, float z) { 456 for (int i=0 ; i<4 ; i++) { 457 int mi = mOffset + i; 458 m[ mi] *= x; 459 m[ 4 + mi] *= y; 460 m[ 8 + mi] *= z; 461 } 462 } 463 464 /** 465 * Translates matrix m by x, y, and z, putting the result in tm 466 * @param tm returns the result 467 * @param tmOffset index into sm where the result matrix starts 468 * @param m source matrix 469 * @param mOffset index into m where the source matrix starts 470 * @param x translation factor x 471 * @param y translation factor y 472 * @param z translation factor z 473 */ 474 public static void translateM(float[] tm, int tmOffset, 475 float[] m, int mOffset, 476 float x, float y, float z) { 477 for (int i=0 ; i<12 ; i++) { 478 tm[tmOffset + i] = m[mOffset + i]; 479 } 480 for (int i=0 ; i<4 ; i++) { 481 int tmi = tmOffset + i; 482 int mi = mOffset + i; 483 tm[12 + tmi] = m[mi] * x + m[4 + mi] * y + m[8 + mi] * z + 484 m[12 + mi]; 485 } 486 } 487 488 /** 489 * Translates matrix m by x, y, and z in place. 490 * @param m matrix 491 * @param mOffset index into m where the matrix starts 492 * @param x translation factor x 493 * @param y translation factor y 494 * @param z translation factor z 495 */ 496 public static void translateM( 497 float[] m, int mOffset, 498 float x, float y, float z) { 499 for (int i=0 ; i<4 ; i++) { 500 int mi = mOffset + i; 501 m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z; 502 } 503 } 504 505 /** 506 * Rotates matrix m by angle a (in degrees) around the axis (x, y, z) 507 * @param rm returns the result 508 * @param rmOffset index into rm where the result matrix starts 509 * @param m source matrix 510 * @param mOffset index into m where the source matrix starts 511 * @param a angle to rotate in degrees 512 * @param x scale factor x 513 * @param y scale factor y 514 * @param z scale factor z 515 */ 516 public static void rotateM(float[] rm, int rmOffset, 517 float[] m, int mOffset, 518 float a, float x, float y, float z) { 519 synchronized(sTemp) { 520 setRotateM(sTemp, 0, a, x, y, z); 521 multiplyMM(rm, rmOffset, m, mOffset, sTemp, 0); 522 } 523 } 524 525 /** 526 * Rotates matrix m in place by angle a (in degrees) 527 * around the axis (x, y, z) 528 * @param m source matrix 529 * @param mOffset index into m where the matrix starts 530 * @param a angle to rotate in degrees 531 * @param x scale factor x 532 * @param y scale factor y 533 * @param z scale factor z 534 */ 535 public static void rotateM(float[] m, int mOffset, 536 float a, float x, float y, float z) { 537 synchronized(sTemp) { 538 setRotateM(sTemp, 0, a, x, y, z); 539 multiplyMM(sTemp, 16, m, mOffset, sTemp, 0); 540 System.arraycopy(sTemp, 16, m, mOffset, 16); 541 } 542 } 543 544 /** 545 * Rotates matrix m by angle a (in degrees) around the axis (x, y, z) 546 * @param rm returns the result 547 * @param rmOffset index into rm where the result matrix starts 548 * @param a angle to rotate in degrees 549 * @param x scale factor x 550 * @param y scale factor y 551 * @param z scale factor z 552 */ 553 public static void setRotateM(float[] rm, int rmOffset, 554 float a, float x, float y, float z) { 555 rm[rmOffset + 3] = 0; 556 rm[rmOffset + 7] = 0; 557 rm[rmOffset + 11]= 0; 558 rm[rmOffset + 12]= 0; 559 rm[rmOffset + 13]= 0; 560 rm[rmOffset + 14]= 0; 561 rm[rmOffset + 15]= 1; 562 a *= (float) (Math.PI / 180.0f); 563 float s = (float) Math.sin(a); 564 float c = (float) Math.cos(a); 565 if (1.0f == x && 0.0f == y && 0.0f == z) { 566 rm[rmOffset + 5] = c; rm[rmOffset + 10]= c; 567 rm[rmOffset + 6] = s; rm[rmOffset + 9] = -s; 568 rm[rmOffset + 1] = 0; rm[rmOffset + 2] = 0; 569 rm[rmOffset + 4] = 0; rm[rmOffset + 8] = 0; 570 rm[rmOffset + 0] = 1; 571 } else if (0.0f == x && 1.0f == y && 0.0f == z) { 572 rm[rmOffset + 0] = c; rm[rmOffset + 10]= c; 573 rm[rmOffset + 8] = s; rm[rmOffset + 2] = -s; 574 rm[rmOffset + 1] = 0; rm[rmOffset + 4] = 0; 575 rm[rmOffset + 6] = 0; rm[rmOffset + 9] = 0; 576 rm[rmOffset + 5] = 1; 577 } else if (0.0f == x && 0.0f == y && 1.0f == z) { 578 rm[rmOffset + 0] = c; rm[rmOffset + 5] = c; 579 rm[rmOffset + 1] = s; rm[rmOffset + 4] = -s; 580 rm[rmOffset + 2] = 0; rm[rmOffset + 6] = 0; 581 rm[rmOffset + 8] = 0; rm[rmOffset + 9] = 0; 582 rm[rmOffset + 10]= 1; 583 } else { 584 float len = length(x, y, z); 585 if (1.0f != len) { 586 float recipLen = 1.0f / len; 587 x *= recipLen; 588 y *= recipLen; 589 z *= recipLen; 590 } 591 float nc = 1.0f - c; 592 float xy = x * y; 593 float yz = y * z; 594 float zx = z * x; 595 float xs = x * s; 596 float ys = y * s; 597 float zs = z * s; 598 rm[rmOffset + 0] = x*x*nc + c; 599 rm[rmOffset + 4] = xy*nc - zs; 600 rm[rmOffset + 8] = zx*nc + ys; 601 rm[rmOffset + 1] = xy*nc + zs; 602 rm[rmOffset + 5] = y*y*nc + c; 603 rm[rmOffset + 9] = yz*nc - xs; 604 rm[rmOffset + 2] = zx*nc - ys; 605 rm[rmOffset + 6] = yz*nc + xs; 606 rm[rmOffset + 10] = z*z*nc + c; 607 } 608 } 609 610 /** 611 * Converts Euler angles to a rotation matrix 612 * @param rm returns the result 613 * @param rmOffset index into rm where the result matrix starts 614 * @param x angle of rotation, in degrees 615 * @param y angle of rotation, in degrees 616 * @param z angle of rotation, in degrees 617 */ 618 public static void setRotateEulerM(float[] rm, int rmOffset, 619 float x, float y, float z) { 620 x *= (float) (Math.PI / 180.0f); 621 y *= (float) (Math.PI / 180.0f); 622 z *= (float) (Math.PI / 180.0f); 623 float cx = (float) Math.cos(x); 624 float sx = (float) Math.sin(x); 625 float cy = (float) Math.cos(y); 626 float sy = (float) Math.sin(y); 627 float cz = (float) Math.cos(z); 628 float sz = (float) Math.sin(z); 629 float cxsy = cx * sy; 630 float sxsy = sx * sy; 631 632 rm[rmOffset + 0] = cy * cz; 633 rm[rmOffset + 1] = -cy * sz; 634 rm[rmOffset + 2] = sy; 635 rm[rmOffset + 3] = 0.0f; 636 637 rm[rmOffset + 4] = cxsy * cz + cx * sz; 638 rm[rmOffset + 5] = -cxsy * sz + cx * cz; 639 rm[rmOffset + 6] = -sx * cy; 640 rm[rmOffset + 7] = 0.0f; 641 642 rm[rmOffset + 8] = -sxsy * cz + sx * sz; 643 rm[rmOffset + 9] = sxsy * sz + sx * cz; 644 rm[rmOffset + 10] = cx * cy; 645 rm[rmOffset + 11] = 0.0f; 646 647 rm[rmOffset + 12] = 0.0f; 648 rm[rmOffset + 13] = 0.0f; 649 rm[rmOffset + 14] = 0.0f; 650 rm[rmOffset + 15] = 1.0f; 651 } 652 653 /** 654 * Define a viewing transformation in terms of an eye point, a center of 655 * view, and an up vector. 656 * 657 * @param rm returns the result 658 * @param rmOffset index into rm where the result matrix starts 659 * @param eyeX eye point X 660 * @param eyeY eye point Y 661 * @param eyeZ eye point Z 662 * @param centerX center of view X 663 * @param centerY center of view Y 664 * @param centerZ center of view Z 665 * @param upX up vector X 666 * @param upY up vector Y 667 * @param upZ up vector Z 668 */ 669 public static void setLookAtM(float[] rm, int rmOffset, 670 float eyeX, float eyeY, float eyeZ, 671 float centerX, float centerY, float centerZ, float upX, float upY, 672 float upZ) { 673 674 // See the OpenGL GLUT documentation for gluLookAt for a description 675 // of the algorithm. We implement it in a straightforward way: 676 677 float fx = centerX - eyeX; 678 float fy = centerY - eyeY; 679 float fz = centerZ - eyeZ; 680 681 // Normalize f 682 float rlf = 1.0f / Matrix.length(fx, fy, fz); 683 fx *= rlf; 684 fy *= rlf; 685 fz *= rlf; 686 687 // compute s = f x up (x means "cross product") 688 float sx = fy * upZ - fz * upY; 689 float sy = fz * upX - fx * upZ; 690 float sz = fx * upY - fy * upX; 691 692 // and normalize s 693 float rls = 1.0f / Matrix.length(sx, sy, sz); 694 sx *= rls; 695 sy *= rls; 696 sz *= rls; 697 698 // compute u = s x f 699 float ux = sy * fz - sz * fy; 700 float uy = sz * fx - sx * fz; 701 float uz = sx * fy - sy * fx; 702 703 rm[rmOffset + 0] = sx; 704 rm[rmOffset + 1] = ux; 705 rm[rmOffset + 2] = -fx; 706 rm[rmOffset + 3] = 0.0f; 707 708 rm[rmOffset + 4] = sy; 709 rm[rmOffset + 5] = uy; 710 rm[rmOffset + 6] = -fy; 711 rm[rmOffset + 7] = 0.0f; 712 713 rm[rmOffset + 8] = sz; 714 rm[rmOffset + 9] = uz; 715 rm[rmOffset + 10] = -fz; 716 rm[rmOffset + 11] = 0.0f; 717 718 rm[rmOffset + 12] = 0.0f; 719 rm[rmOffset + 13] = 0.0f; 720 rm[rmOffset + 14] = 0.0f; 721 rm[rmOffset + 15] = 1.0f; 722 723 translateM(rm, rmOffset, -eyeX, -eyeY, -eyeZ); 724 } 725} 726