Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 // based on code from | |
| 6 // http://code.google.com/p/closure-library/source/browse/trunk/closure/goog/vec /mat4.js | |
| 7 | |
| 8 /** | |
| 9 * Thrown if you attempt to normalize a zero length vector. | |
| 10 */ | |
| 11 class ZeroLengthVectorException implements Exception { | |
| 12 ZeroLengthVectorException() {} | |
| 13 } | |
| 14 | |
| 15 /** | |
| 16 * Thrown if you attempt to invert a singular matrix. (A | |
| 17 * singular matrix has no inverse.) | |
| 18 */ | |
| 19 class SingularMatrixException implements Exception { | |
| 20 SingularMatrixException() {} | |
| 21 } | |
| 22 | |
| 23 /** | |
| 24 * 3 dimensional vector. | |
| 25 */ | |
| 26 class Vector3 { | |
| 27 final double x; | |
|
Jacob
2011/12/12 22:59:14
One more high level comment. Is there a good reas
mattsh
2011/12/12 23:06:35
I think for consistency and interoperability with
| |
| 28 final double y; | |
| 29 final double z; | |
| 30 | |
| 31 // TODO - should be const, but cannot because of | |
| 32 // bug http://code.google.com/p/dart/issues/detail?id=777 | |
|
Bob Nystrom
2011/12/12 21:46:09
According to the bug, this is fixed now.
| |
| 33 Vector3(double x, double y, double z) : x = x, y = y, z = z {} | |
|
Jacob
2011/12/12 18:38:17
replace " {}" with ";"
mattsh
2011/12/12 19:14:45
Done.
Bob Nystrom
2011/12/12 21:46:09
Why not just use this.x, this.y, this.z?
mattsh
2011/12/12 22:48:26
Currently the this.x style syntax does not lift th
Jacob
2011/12/12 22:59:14
is there a good reason why these are double instea
mattsh
2011/12/12 23:06:35
See above
| |
| 34 | |
| 35 double magnitude() { | |
|
Jacob
2011/12/12 18:38:17
switch short one liners to use => syntax
mattsh
2011/12/12 19:14:45
Prefer non-arrow syntax here, since it is consiste
Bob Nystrom
2011/12/12 21:46:09
Personally, I'd prefer arrow here too (and elsewhe
Bob Nystrom
2011/12/12 21:46:09
Should this be a getter? Also, I'd add magnitudeSq
mattsh
2011/12/12 22:48:26
OK, switch to arrow syntax.
mattsh
2011/12/12 22:48:26
I think it's better to keep it a method, to make i
| |
| 36 return Math.sqrt(x*x + y*y + z*z); | |
| 37 } | |
| 38 | |
| 39 Vector3 normalize() { | |
| 40 double len = magnitude(); | |
| 41 if (len == 0.0) { | |
| 42 throw new ZeroLengthVectorException(); | |
| 43 } | |
| 44 return new Vector3(x/len, y/len, z/len); | |
| 45 } | |
| 46 | |
| 47 Vector3 operator negate() { | |
| 48 return new Vector3(-x,-y,-z); | |
|
Bob Nystrom
2011/12/12 21:46:09
Space after comma.
mattsh
2011/12/12 22:48:26
Done.
| |
| 49 } | |
| 50 | |
| 51 Vector3 operator -(Vector3 other) { | |
| 52 return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z); | |
|
Bob Nystrom
2011/12/12 21:46:09
Get rid of "this.".
mattsh
2011/12/12 22:48:26
Done.
| |
| 53 } | |
| 54 | |
| 55 Vector3 cross(Vector3 other) { | |
| 56 double xResult = y * other.z - z * other.y; | |
|
Bob Nystrom
2011/12/12 21:46:09
"final" instead of "double".
mattsh
2011/12/12 22:48:26
I think I prefer writing the type here.
| |
| 57 double yResult = z * other.x - x * other.z; | |
| 58 double zResult = x * other.y - y * other.x; | |
| 59 return new Vector3(xResult, yResult, zResult); | |
| 60 } | |
| 61 | |
| 62 String toString() { | |
| 63 return "Vector3($x,$y,$z)"; | |
|
Jacob
2011/12/12 22:59:14
one more style nit. why not "($x, $y, $z)" instead
| |
| 64 } | |
| 65 } | |
| 66 | |
| 67 /** | |
| 68 * A 4x4 transformation matrix (for use with webgl) | |
| 69 * | |
| 70 * We label the elements of the matrix as follows: | |
| 71 * | |
| 72 * m00 m01 m02 m03 | |
|
Bob Nystrom
2011/12/12 21:46:09
Indent these two more and dartdoc will recognize i
mattsh
2011/12/12 22:48:26
Done.
| |
| 73 * m10 m11 m12 m13 | |
| 74 * m20 m21 m22 m23 | |
| 75 * m30 m31 m32 m33 | |
| 76 * | |
| 77 * These are stored in a 16 element Float32Array, in column major | |
|
Bob Nystrom
2011/12/12 21:46:09
Put Float32Array in square brackets to cross-link.
mattsh
2011/12/12 22:48:26
Done.
| |
| 78 * order, so they are ordered like this: | |
| 79 * | |
| 80 * [ m00,m10,m20,m30, m11,m21,m31,m41, m02,m12,m22,m32, m03,m13,m23,m33 ] | |
| 81 * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
| 82 * | |
| 83 * We use column major order because that is what WebGL APIs expect. | |
| 84 * | |
| 85 */ | |
| 86 class Matrix4 { | |
| 87 final Float32Array buf; | |
|
Bob Nystrom
2011/12/12 21:46:09
"buffer" or "elements"?
mattsh
2011/12/12 22:48:26
Tried elements, but actually it just doesn't look
| |
| 88 | |
| 89 /** | |
| 90 * returns the index into [buf] for a given | |
| 91 * row and column. | |
| 92 */ | |
| 93 static int rc(int row, int col) => row + col * 4; | |
|
Jacob
2011/12/12 18:38:17
add a leading _?
mattsh
2011/12/12 19:14:45
Prefer to keep it public.
Bob Nystrom
2011/12/12 21:46:09
If you want this to be public, I would give it a m
mattsh
2011/12/12 22:48:26
Done.
| |
| 94 | |
| 95 double get m00() => buf[rc(0, 0)]; | |
| 96 double get m01() => buf[rc(0, 1)]; | |
| 97 double get m02() => buf[rc(0, 2)]; | |
| 98 double get m03() => buf[rc(0, 3)]; | |
| 99 double get m10() => buf[rc(1, 0)]; | |
| 100 double get m11() => buf[rc(1, 1)]; | |
| 101 double get m12() => buf[rc(1, 2)]; | |
| 102 double get m13() => buf[rc(1, 3)]; | |
| 103 double get m20() => buf[rc(2, 0)]; | |
| 104 double get m21() => buf[rc(2, 1)]; | |
| 105 double get m22() => buf[rc(2, 2)]; | |
| 106 double get m23() => buf[rc(2, 3)]; | |
| 107 double get m30() => buf[rc(3, 0)]; | |
| 108 double get m31() => buf[rc(3, 1)]; | |
| 109 double get m32() => buf[rc(3, 2)]; | |
| 110 double get m33() => buf[rc(3, 3)]; | |
| 111 | |
| 112 void set m00(double m) { buf[rc(0, 0)] = m; } | |
| 113 void set m01(double m) { buf[rc(0, 1)] = m; } | |
| 114 void set m02(double m) { buf[rc(0, 2)] = m; } | |
| 115 void set m03(double m) { buf[rc(0, 3)] = m; } | |
| 116 void set m10(double m) { buf[rc(1, 0)] = m; } | |
| 117 void set m11(double m) { buf[rc(1, 1)] = m; } | |
| 118 void set m12(double m) { buf[rc(1, 2)] = m; } | |
| 119 void set m13(double m) { buf[rc(1, 3)] = m; } | |
| 120 void set m20(double m) { buf[rc(2, 0)] = m; } | |
| 121 void set m21(double m) { buf[rc(2, 1)] = m; } | |
| 122 void set m22(double m) { buf[rc(2, 2)] = m; } | |
| 123 void set m23(double m) { buf[rc(2, 3)] = m; } | |
| 124 void set m30(double m) { buf[rc(3, 0)] = m; } | |
| 125 void set m31(double m) { buf[rc(3, 1)] = m; } | |
| 126 void set m32(double m) { buf[rc(3, 2)] = m; } | |
| 127 void set m33(double m) { buf[rc(3, 3)] = m; } | |
| 128 | |
| 129 String toString() { | |
| 130 List<String> rows = new List(); | |
| 131 for (int row = 0; row < 4; row++) { | |
| 132 List<String> items = new List(); | |
| 133 for (int col = 0; col < 4; col++) { | |
| 134 double v = buf[rc(row, col)]; | |
| 135 if (v.abs() < 1e-16) { | |
| 136 v = 0.0; | |
| 137 } | |
| 138 String display; | |
| 139 try { | |
| 140 display = v.toStringAsPrecision(4); | |
| 141 } catch (Object e) { | |
| 142 // TODO - remove this once toStringAsPrecision is implemented in vm | |
| 143 display = v.toString(); | |
| 144 } | |
| 145 items.add(display); | |
| 146 } | |
| 147 rows.add("| ${Strings.join(items, ", ")} |"); | |
| 148 } | |
| 149 return "Matrix4:\n${Strings.join(rows, '\n')}"; | |
| 150 } | |
| 151 | |
| 152 /** | |
| 153 * Constructs a new Matrix4 with all entries initialized | |
| 154 * to zero. | |
| 155 */ | |
| 156 Matrix4() : buf = new Float32Array(16) {} | |
|
Jacob
2011/12/12 18:38:17
move constructors above members and replace " {}"
mattsh
2011/12/12 19:14:45
Done.
| |
| 157 | |
| 158 /** | |
| 159 * Cosntructs a new Matrix4 that represents the identity transformation | |
| 160 * (all the diagonal entries are 1, and everything else is zero). | |
| 161 */ | |
| 162 static Matrix4 identity() { | |
|
Jacob
2011/12/12 18:38:17
change statics for identity, rotation and transpos
mattsh
2011/12/12 19:14:45
Actually, prefer these to be static methods, not f
Jacob
2011/12/12 22:59:14
One advantage of making the factory constructors i
| |
| 163 Matrix4 m = new Matrix4(); | |
| 164 m.m00 = 1.0; | |
| 165 m.m11 = 1.0; | |
| 166 m.m22 = 1.0; | |
| 167 m.m33 = 1.0; | |
| 168 return m; | |
| 169 } | |
| 170 | |
| 171 /** | |
| 172 * Constructs a new Matrix4 that represents a rotation around an axis. | |
| 173 * | |
| 174 * [degrees] number of degrees to rotate | |
| 175 * [axis] direction of axis of rotation (must not be zero length) | |
| 176 */ | |
| 177 static Matrix4 rotation(double degrees, Vector3 axis) { | |
| 178 double radians = degrees / 180.0 * Math.PI; | |
| 179 axis = axis.normalize(); | |
| 180 | |
| 181 double x = axis.x; | |
| 182 double y = axis.y; | |
| 183 double z = axis.z; | |
| 184 double s = Math.sin(radians); | |
| 185 double c = Math.cos(radians); | |
| 186 double t = 1 - c; | |
| 187 | |
| 188 Matrix4 m = new Matrix4(); | |
| 189 m.m00 = x * x * t + c; | |
| 190 m.m10 = x * y * t + z * s; | |
| 191 m.m20 = x * z * t - y * s; | |
| 192 | |
| 193 m.m01 = x * y * t - z * s; | |
| 194 m.m11 = y * y * t + c; | |
| 195 m.m21 = y * z * t + x * s; | |
| 196 | |
| 197 m.m02 = x * z * t + y * s; | |
| 198 m.m12 = y * z * t - x * s; | |
| 199 m.m22 = z * z * t + c; | |
| 200 | |
| 201 m.m33 = 1.0; | |
| 202 return m; | |
| 203 } | |
| 204 | |
| 205 /** | |
| 206 * Constructs a new Matrix4 that represents a translation. | |
| 207 * | |
| 208 * [v] vector representing which direction to move and how much to move | |
| 209 */ | |
| 210 static Matrix4 translation(Vector3 v) { | |
| 211 Matrix4 m = identity(); | |
| 212 m.m03 = v.x; | |
| 213 m.m13 = v.y; | |
| 214 m.m23 = v.z; | |
| 215 return m; | |
| 216 } | |
| 217 | |
| 218 /** | |
| 219 * returns the transpose of this matrix | |
| 220 */ | |
| 221 Matrix4 transpose() { | |
| 222 Matrix4 m = new Matrix4(); | |
| 223 for (int row = 0; row < 4; row++) { | |
| 224 for (int col = 0; col < 4; col++) { | |
| 225 m.buf[rc(col, row)] = this.buf[rc(row, col)]; | |
| 226 } | |
| 227 } | |
| 228 return m; | |
| 229 } | |
| 230 | |
| 231 /** | |
| 232 * Returns result of multiplication of this matrix | |
| 233 * by another matrix. | |
| 234 * | |
| 235 * In this equation: | |
| 236 * | |
| 237 * C = A * B | |
| 238 * | |
| 239 * C is the result of multiplying A * B. | |
| 240 * A is this matrix | |
| 241 * B is another matrix | |
| 242 * | |
| 243 */ | |
| 244 Matrix4 operator *(Matrix4 matrixB) { | |
| 245 Matrix4 matrixC = new Matrix4(); | |
| 246 Float32Array bufA = this.buf; | |
| 247 Float32Array bufB = matrixB.buf; | |
| 248 Float32Array bufC = matrixC.buf; | |
| 249 for (int row = 0; row < 4; row++) { | |
| 250 for (int col = 0; col < 4; col++) { | |
| 251 for (int i = 0; i < 4; i++) { | |
| 252 bufC[rc(row, col)] += bufA[rc(row, i)] * bufB[rc(i, col)]; | |
| 253 } | |
| 254 } | |
| 255 } | |
| 256 return matrixC; | |
| 257 } | |
| 258 | |
| 259 /** | |
| 260 * Constructs a 4x4 matrix matrix so that the eye is 'looking at' a | |
| 261 * given center point. (What this means is that the returned matrix can be | |
| 262 * used transform points from world coordinates to a new coordinate system | |
| 263 * where the eye is at the origin, and the negative z-axis of the new | |
| 264 * coordinate system goes from the eye towards the center point.) | |
| 265 * | |
| 266 * [eye] position of the eye (i.e. camera origin). | |
| 267 * [center] point to aim the camera at. | |
| 268 * [up] vector that identifies the up direction of the camera | |
| 269 */ | |
| 270 static Matrix4 lookAt(Vector3 eye, Vector3 center, Vector3 up) { | |
|
Jacob
2011/12/12 18:38:17
make factory constructor
mattsh
2011/12/12 19:14:45
see above
| |
| 271 // Compute the z basis vector. (The z-axis negative direction is | |
| 272 // from eye to center point.) | |
| 273 Vector3 zBasis = (eye - center).normalize(); | |
| 274 | |
| 275 // Compute x basis. (The positive x-axis points right.) | |
| 276 Vector3 xBasis = up.cross(zBasis).normalize(); | |
| 277 | |
| 278 // Compute the y basis. (The positive y-axis points approximately the same | |
| 279 // direction as the supplied [up] direction, and is perpendicular to z and | |
| 280 // x.) | |
| 281 Vector3 yBasis = zBasis.cross(xBasis); | |
| 282 | |
| 283 // We now have an orthonormal basis. | |
| 284 Matrix4 b = new Matrix4(); | |
| 285 b.m00 = xBasis.x; b.m01 = xBasis.y; b.m02 = xBasis.z; | |
| 286 b.m10 = yBasis.x; b.m11 = yBasis.y; b.m12 = yBasis.z; | |
| 287 b.m20 = zBasis.x; b.m21 = zBasis.y; b.m22 = zBasis.z; | |
| 288 b.m33 = 1.0; | |
| 289 | |
| 290 // Before switching to the new basis, first translate by the negation | |
| 291 // of the eye point. (This will put the eye at the origin of the | |
| 292 // new coordinate system.) | |
| 293 return b * Matrix4.translation(-eye); | |
| 294 } | |
| 295 | |
| 296 /** | |
| 297 * Makse a 4x4 matrix perspective projection matrix given a field of view and | |
| 298 * aspect ratio. | |
| 299 * | |
| 300 * [fovyDegrees] field of view (in degrees) of the y-axis | |
| 301 * [aspectRatio] width to height aspect ratio. | |
| 302 * [zNear] distance to the near clipping plane. | |
| 303 * [zFar] distance to the far clipping plane. | |
| 304 */ | |
| 305 static Matrix4 perspective(double fovyDegrees, double aspectRatio, | |
|
Jacob
2011/12/12 18:38:17
factory constructor
mattsh
2011/12/12 19:14:45
see above
| |
| 306 double zNear, double zFar) { | |
| 307 double yTop = Math.tan(fovyDegrees * Math.PI / 180.0 / 2.0) * zNear; | |
| 308 double xRight = aspectRatio * yTop; | |
| 309 double zDepth = zFar - zNear; | |
| 310 | |
| 311 Matrix4 m = new Matrix4(); | |
| 312 m.m00 = zNear / xRight; | |
| 313 m.m11 = zNear / yTop; | |
| 314 m.m22 = -(zFar + zNear) / zDepth; | |
| 315 m.m23 = -(2 * zNear * zFar) / zDepth; | |
| 316 m.m32 = -1; | |
| 317 return m; | |
| 318 } | |
| 319 | |
| 320 /** | |
| 321 * Returns the inverse of this matrix. | |
| 322 */ | |
| 323 Matrix4 inverse() { | |
| 324 double a0 = m00 * m11 - m10 * m01; | |
| 325 double a1 = m00 * m21 - m20 * m01; | |
| 326 double a2 = m00 * m31 - m30 * m01; | |
| 327 double a3 = m10 * m21 - m20 * m11; | |
| 328 double a4 = m10 * m31 - m30 * m11; | |
| 329 double a5 = m20 * m31 - m30 * m21; | |
| 330 | |
| 331 double b0 = m02 * m13 - m12 * m03; | |
| 332 double b1 = m02 * m23 - m22 * m03; | |
| 333 double b2 = m02 * m33 - m32 * m03; | |
| 334 double b3 = m12 * m23 - m22 * m13; | |
| 335 double b4 = m12 * m33 - m32 * m13; | |
| 336 double b5 = m22 * m33 - m32 * m23; | |
| 337 | |
| 338 // compute determinant | |
|
Bob Nystrom
2011/12/12 21:46:09
"Compute determinant."
mattsh
2011/12/12 22:48:26
Done.
| |
| 339 double det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0; | |
| 340 if (det == 0) { | |
| 341 throw new SingularMatrixException(); | |
| 342 } | |
| 343 | |
| 344 Matrix4 m = new Matrix4(); | |
| 345 m.m00 = (m11 * b5 - m21 * b4 + m31 * b3) / det; | |
| 346 m.m10 = (-m10 * b5 + m20 * b4 - m30 * b3) / det; | |
| 347 m.m20 = (m13 * a5 - m23 * a4 + m33 * a3) / det; | |
| 348 m.m30 = (-m12 * a5 + m22 * a4 - m32 * a3) / det; | |
| 349 | |
| 350 m.m01 = (-m01 * b5 + m21 * b2 - m31 * b1) / det; | |
| 351 m.m11 = (m00 * b5 - m20 * b2 + m30 * b1) / det; | |
| 352 m.m21 = (-m03 * a5 + m23 * a2 - m33 * a1) / det; | |
| 353 m.m31 = (m02 * a5 - m22 * a2 + m32 * a1) / det; | |
| 354 | |
| 355 m.m02 = (m01 * b4 - m11 * b2 + m31 * b0) / det; | |
| 356 m.m12 = (-m00 * b4 + m10 * b2 - m30 * b0) / det; | |
| 357 m.m22 = (m03 * a4 - m13 * a2 + m33 * a0) / det; | |
| 358 m.m32 = (-m02 * a4 + m12 * a2 - m32 * a0) / det; | |
| 359 | |
| 360 m.m03 = (-m01 * b3 + m11 * b1 - m21 * b0) / det; | |
| 361 m.m13 = (m00 * b3 - m10 * b1 + m20 * b0) / det; | |
| 362 m.m23 = (-m03 * a3 + m13 * a1 - m23 * a0) / det; | |
| 363 m.m33 = (m02 * a3 - m12 * a1 + m22 * a0) / det; | |
| 364 | |
| 365 return m; | |
| 366 } | |
| 367 } | |
| OLD | NEW |