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