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