Matrix.java revision 54b6cfa9a9e5b861a9930af873580d6dc20f773c
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 * Computes the length of a vector 334 * 335 * @param x x coordinate of a vector 336 * @param y y coordinate of a vector 337 * @param z z coordinate of a vector 338 * @return the length of a vector 339 */ 340 public static float length(float x, float y, float z) { 341 return (float) Math.sqrt(x * x + y * y + z * z); 342 } 343 344 /** 345 * Sets matrix m to the identity matrix. 346 * @param sm returns the result 347 * @param smOffset index into sm where the result matrix starts 348 */ 349 public static void setIdentityM(float[] sm, int smOffset) { 350 for (int i=0 ; i<16 ; i++) { 351 sm[smOffset + i] = 0; 352 } 353 for(int i = 0; i < 16; i += 5) { 354 sm[smOffset + i] = 1.0f; 355 } 356 } 357 358 /** 359 * Scales matrix m by sx, sy, and sz, putting the result in sm 360 * @param sm returns the result 361 * @param smOffset index into sm where the result matrix starts 362 * @param m source matrix 363 * @param mOffset index into m where the source matrix starts 364 * @param x scale factor x 365 * @param y scale factor y 366 * @param z scale factor z 367 */ 368 public static void scaleM(float[] sm, int smOffset, 369 float[] m, int mOffset, 370 float x, float y, float z) { 371 for (int i=0 ; i<4 ; i++) { 372 int smi = smOffset + i; 373 int mi = mOffset + i; 374 sm[ smi] = m[ mi] * x; 375 sm[ 4 + smi] = m[ 4 + mi] * y; 376 sm[ 8 + smi] = m[ 8 + mi] * z; 377 sm[12 + smi] = m[12 + mi]; 378 } 379 } 380 381 /** 382 * Scales matrix m in place by sx, sy, and sz 383 * @param m matrix to scale 384 * @param mOffset index into m where the matrix starts 385 * @param x scale factor x 386 * @param y scale factor y 387 * @param z scale factor z 388 */ 389 public static void scaleM(float[] m, int mOffset, 390 float x, float y, float z) { 391 for (int i=0 ; i<4 ; i++) { 392 int mi = mOffset + i; 393 m[ mi] *= x; 394 m[ 4 + mi] *= y; 395 m[ 8 + mi] *= z; 396 } 397 } 398 399 /** 400 * Translates matrix m by sx, sy, and sz, putting the result in tm 401 * @param tm returns the result 402 * @param tmOffset index into sm where the result matrix starts 403 * @param m source matrix 404 * @param mOffset index into m where the source matrix starts 405 * @param x translation factor x 406 * @param y translation factor y 407 * @param z translation factor z 408 */ 409 public static void translateM(float[] tm, int tmOffset, 410 float[] m, int mOffset, 411 float x, float y, float z) { 412 for (int i=0 ; i<4 ; i++) { 413 int tmi = tmOffset + i; 414 int mi = mOffset + i; 415 tm[12 + tmi] = m[mi] * x + m[4 + mi] * y + m[8 + mi] * z + 416 m[12 + mi]; 417 } 418 } 419 420 /** 421 * Translates matrix m by sx, sy, and sz in place. 422 * @param m matrix 423 * @param mOffset index into m where the matrix starts 424 * @param x translation factor x 425 * @param y translation factor y 426 * @param z translation factor z 427 */ 428 public static void translateM( 429 float[] m, int mOffset, 430 float x, float y, float z) { 431 for (int i=0 ; i<4 ; i++) { 432 int mi = mOffset + i; 433 m[12 + mi] += m[mi] * x + m[4 + mi] * y + m[8 + mi] * z; 434 } 435 } 436 437 /** 438 * Rotates matrix m by angle a (in degrees) around the axis (x, y, z) 439 * @param rm returns the result 440 * @param rmOffset index into rm where the result matrix starts 441 * @param m source matrix 442 * @param mOffset index into m where the source matrix starts 443 * @param a angle to rotate in degrees 444 * @param x scale factor x 445 * @param y scale factor y 446 * @param z scale factor z 447 */ 448 public static void rotateM(float[] rm, int rmOffset, 449 float[] m, int mOffset, 450 float a, float x, float y, float z) { 451 float[] r = new float[16]; 452 setRotateM(r, 0, a, x, y, z); 453 multiplyMM(rm, rmOffset, m, mOffset, r, 0); 454 } 455 456 /** 457 * Rotates matrix m in place by angle a (in degrees) 458 * around the axis (x, y, z) 459 * @param m source matrix 460 * @param mOffset index into m where the matrix starts 461 * @param a angle to rotate in degrees 462 * @param x scale factor x 463 * @param y scale factor y 464 * @param z scale factor z 465 */ 466 public static void rotateM(float[] m, int mOffset, 467 float a, float x, float y, float z) { 468 float[] temp = new float[32]; 469 setRotateM(temp, 0, a, x, y, z); 470 multiplyMM(temp, 16, m, mOffset, temp, 0); 471 System.arraycopy(temp, 16, m, mOffset, 16); 472 } 473 474 /** 475 * Rotates matrix m by angle a (in degrees) around the axis (x, y, z) 476 * @param rm returns the result 477 * @param rmOffset index into rm where the result matrix starts 478 * @param a angle to rotate in degrees 479 * @param x scale factor x 480 * @param y scale factor y 481 * @param z scale factor z 482 */ 483 public static void setRotateM(float[] rm, int rmOffset, 484 float a, float x, float y, float z) { 485 rm[rmOffset + 3] = 0; 486 rm[rmOffset + 7] = 0; 487 rm[rmOffset + 11]= 0; 488 rm[rmOffset + 12]= 0; 489 rm[rmOffset + 13]= 0; 490 rm[rmOffset + 14]= 0; 491 rm[rmOffset + 15]= 1; 492 a *= (float) (Math.PI / 180.0f); 493 float s = (float) Math.sin(a); 494 float c = (float) Math.cos(a); 495 if (1.0f == x && 0.0f == y && 0.0f == z) { 496 rm[rmOffset + 5] = c; rm[rmOffset + 10]= c; 497 rm[rmOffset + 6] = s; rm[rmOffset + 9] = -s; 498 rm[rmOffset + 1] = 0; rm[rmOffset + 2] = 0; 499 rm[rmOffset + 4] = 0; rm[rmOffset + 8] = 0; 500 rm[rmOffset + 0] = 1; 501 } else if (0.0f == x && 1.0f == y && 0.0f == z) { 502 rm[rmOffset + 0] = c; rm[rmOffset + 10]= c; 503 rm[rmOffset + 8] = s; rm[rmOffset + 2] = -s; 504 rm[rmOffset + 1] = 0; rm[rmOffset + 4] = 0; 505 rm[rmOffset + 6] = 0; rm[rmOffset + 9] = 0; 506 rm[rmOffset + 5] = 1; 507 } else if (0.0f == x && 0.0f == y && 1.0f == z) { 508 rm[rmOffset + 0] = c; rm[rmOffset + 5] = c; 509 rm[rmOffset + 1] = s; rm[rmOffset + 4] = -s; 510 rm[rmOffset + 2] = 0; rm[rmOffset + 6] = 0; 511 rm[rmOffset + 8] = 0; rm[rmOffset + 9] = 0; 512 rm[rmOffset + 10]= 1; 513 } else { 514 float len = length(x, y, z); 515 if (1.0f != len) { 516 float recipLen = 1.0f / len; 517 x *= recipLen; 518 y *= recipLen; 519 z *= recipLen; 520 } 521 float nc = 1.0f - c; 522 float xy = x * y; 523 float yz = y * z; 524 float zx = z * x; 525 float xs = x * s; 526 float ys = y * s; 527 float zs = z * s; 528 rm[rmOffset + 0] = x*x*nc + c; 529 rm[rmOffset + 4] = xy*nc - zs; 530 rm[rmOffset + 8] = zx*nc + ys; 531 rm[rmOffset + 1] = xy*nc + zs; 532 rm[rmOffset + 5] = y*y*nc + c; 533 rm[rmOffset + 9] = yz*nc - xs; 534 rm[rmOffset + 2] = zx*nc - ys; 535 rm[rmOffset + 6] = yz*nc + xs; 536 rm[rmOffset + 10] = z*z*nc + c; 537 } 538 } 539 540 /** 541 * Converts Euler angles to a rotation matrix 542 * @param rm returns the result 543 * @param rmOffset index into rm where the result matrix starts 544 * @param x angle of rotation, in degrees 545 * @param y angle of rotation, in degrees 546 * @param z angle of rotation, in degrees 547 */ 548 public static void setRotateEulerM(float[] rm, int rmOffset, 549 float x, float y, float z) { 550 x *= (float) (Math.PI / 180.0f); 551 y *= (float) (Math.PI / 180.0f); 552 z *= (float) (Math.PI / 180.0f); 553 float cx = (float) Math.cos(x); 554 float sx = (float) Math.sin(x); 555 float cy = (float) Math.cos(y); 556 float sy = (float) Math.sin(y); 557 float cz = (float) Math.cos(z); 558 float sz = (float) Math.sin(z); 559 float cxsy = cx * sy; 560 float sxsy = sx * sy; 561 562 rm[rmOffset + 0] = cy * cz; 563 rm[rmOffset + 1] = -cy * sz; 564 rm[rmOffset + 2] = sy; 565 rm[rmOffset + 3] = 0.0f; 566 567 rm[rmOffset + 4] = cxsy * cz + cx * sz; 568 rm[rmOffset + 5] = -cxsy * sz + cx * cz; 569 rm[rmOffset + 6] = -sx * cy; 570 rm[rmOffset + 7] = 0.0f; 571 572 rm[rmOffset + 8] = -sxsy * cz + sx * sz; 573 rm[rmOffset + 9] = sxsy * sz + sx * cz; 574 rm[rmOffset + 10] = cx * cy; 575 rm[rmOffset + 11] = 0.0f; 576 577 rm[rmOffset + 12] = 0.0f; 578 rm[rmOffset + 13] = 0.0f; 579 rm[rmOffset + 14] = 0.0f; 580 rm[rmOffset + 15] = 1.0f; 581 } 582} 583