├── .gitignore ├── .npmignore ├── build ├── vecmath.js └── vecmath.min.js ├── lib ├── Matrix3.js ├── Matrix4.js ├── Quaternion.js ├── Vector2.js ├── Vector3.js ├── Vector4.js ├── common.js └── index.js ├── package.json ├── readme.md └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | npm-debug.log -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | test.js -------------------------------------------------------------------------------- /build/vecmath.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.vecmath=e():"undefined"!=typeof global?global.vecmath=e():"undefined"!=typeof self&&(self.vecmath=e())}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0.999999) { 1045 | this.x = 0; 1046 | this.y = 0; 1047 | this.z = 0; 1048 | this.w = 1; 1049 | return this; 1050 | } else { 1051 | tmpvec.copy(a).cross(b); 1052 | this.x = tmpvec.x; 1053 | this.y = tmpvec.y; 1054 | this.z = tmpvec.z; 1055 | this.w = 1 + dot; 1056 | return this.normalize(); 1057 | } 1058 | }; 1059 | 1060 | quat.setAxes = function(view, right, up) { 1061 | var m = tmpMat3.val; 1062 | m[0] = right.x; 1063 | m[3] = right.y; 1064 | m[6] = right.z; 1065 | 1066 | m[1] = up.x; 1067 | m[4] = up.y; 1068 | m[7] = up.z; 1069 | 1070 | m[2] = -view.x; 1071 | m[5] = -view.y; 1072 | m[8] = -view.z; 1073 | 1074 | return this.fromMat3(tmpMat3).normalize(); 1075 | }; 1076 | 1077 | quat.identity = function() { 1078 | this.x = this.y = this.z = 0; 1079 | this.w = 1; 1080 | return this; 1081 | }; 1082 | 1083 | quat.setAxisAngle = function(axis, rad) { 1084 | rad = rad * 0.5; 1085 | var s = Math.sin(rad); 1086 | this.x = s * axis.x; 1087 | this.y = s * axis.y; 1088 | this.z = s * axis.z; 1089 | this.w = Math.cos(rad); 1090 | return this; 1091 | }; 1092 | 1093 | quat.multiply = function(b) { 1094 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 1095 | bx = b.x, by = b.y, bz = b.z, bw = b.w; 1096 | 1097 | this.x = ax * bw + aw * bx + ay * bz - az * by; 1098 | this.y = ay * bw + aw * by + az * bx - ax * bz; 1099 | this.z = az * bw + aw * bz + ax * by - ay * bx; 1100 | this.w = aw * bw - ax * bx - ay * by - az * bz; 1101 | return this; 1102 | }; 1103 | 1104 | quat.slerp = function (b, t) { 1105 | // benchmarks: 1106 | // http://jsperf.com/quaternion-slerp-implementations 1107 | 1108 | var ax = this.x, ay = this.y, az = this.y, aw = this.y, 1109 | bx = b.x, by = b.y, bz = b.z, bw = b.w; 1110 | 1111 | var omega, cosom, sinom, scale0, scale1; 1112 | 1113 | // calc cosine 1114 | cosom = ax * bx + ay * by + az * bz + aw * bw; 1115 | // adjust signs (if necessary) 1116 | if ( cosom < 0.0 ) { 1117 | cosom = -cosom; 1118 | bx = - bx; 1119 | by = - by; 1120 | bz = - bz; 1121 | bw = - bw; 1122 | } 1123 | // calculate coefficients 1124 | if ( (1.0 - cosom) > 0.000001 ) { 1125 | // standard case (slerp) 1126 | omega = Math.acos(cosom); 1127 | sinom = Math.sin(omega); 1128 | scale0 = Math.sin((1.0 - t) * omega) / sinom; 1129 | scale1 = Math.sin(t * omega) / sinom; 1130 | } else { 1131 | // "from" and "to" quaternions are very close 1132 | // ... so we can do a linear interpolation 1133 | scale0 = 1.0 - t; 1134 | scale1 = t; 1135 | } 1136 | // calculate final values 1137 | this.x = scale0 * ax + scale1 * bx; 1138 | this.y = scale0 * ay + scale1 * by; 1139 | this.z = scale0 * az + scale1 * bz; 1140 | this.w = scale0 * aw + scale1 * bw; 1141 | return this; 1142 | }; 1143 | 1144 | quat.invert = function() { 1145 | var a0 = this.x, a1 = this.y, a2 = this.z, a3 = this.w, 1146 | dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, 1147 | invDot = dot ? 1.0/dot : 0; 1148 | 1149 | // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 1150 | 1151 | this.x = -a0*invDot; 1152 | this.y = -a1*invDot; 1153 | this.z = -a2*invDot; 1154 | this.w = a3*invDot; 1155 | return this; 1156 | }; 1157 | 1158 | quat.conjugate = function() { 1159 | this.x = -this.x; 1160 | this.y = -this.y; 1161 | this.z = -this.z; 1162 | return this; 1163 | }; 1164 | 1165 | quat.rotateX = function (rad) { 1166 | rad *= 0.5; 1167 | 1168 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 1169 | bx = Math.sin(rad), bw = Math.cos(rad); 1170 | 1171 | this.x = ax * bw + aw * bx; 1172 | this.y = ay * bw + az * bx; 1173 | this.z = az * bw - ay * bx; 1174 | this.w = aw * bw - ax * bx; 1175 | return this; 1176 | }; 1177 | 1178 | quat.rotateY = function (rad) { 1179 | rad *= 0.5; 1180 | 1181 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 1182 | by = Math.sin(rad), bw = Math.cos(rad); 1183 | 1184 | this.x = ax * bw - az * by; 1185 | this.y = ay * bw + aw * by; 1186 | this.z = az * bw + ax * by; 1187 | this.w = aw * bw - ay * by; 1188 | return this; 1189 | }; 1190 | 1191 | quat.rotateZ = function (rad) { 1192 | rad *= 0.5; 1193 | 1194 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 1195 | bz = Math.sin(rad), bw = Math.cos(rad); 1196 | 1197 | this.x = ax * bw + ay * bz; 1198 | this.y = ay * bw - ax * bz; 1199 | this.z = az * bw + aw * bz; 1200 | this.w = aw * bw - az * bz; 1201 | return this; 1202 | }; 1203 | 1204 | quat.calculateW = function () { 1205 | var x = this.x, y = this.y, z = this.z; 1206 | 1207 | this.x = x; 1208 | this.y = y; 1209 | this.z = z; 1210 | this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); 1211 | return this; 1212 | }; 1213 | 1214 | quat.fromMat3 = function(mat) { 1215 | // benchmarks: 1216 | // http://jsperf.com/typed-array-access-speed 1217 | // http://jsperf.com/conversion-of-3x3-matrix-to-quaternion 1218 | 1219 | // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes 1220 | // article "Quaternion Calculus and Fast Animation". 1221 | var m = mat.val, 1222 | fTrace = m[0] + m[4] + m[8]; 1223 | var fRoot; 1224 | 1225 | if ( fTrace > 0.0 ) { 1226 | // |w| > 1/2, may as well choose w > 1/2 1227 | fRoot = Math.sqrt(fTrace + 1.0); // 2w 1228 | this.w = 0.5 * fRoot; 1229 | fRoot = 0.5/fRoot; // 1/(4w) 1230 | this.x = (m[7]-m[5])*fRoot; 1231 | this.y = (m[2]-m[6])*fRoot; 1232 | this.z = (m[3]-m[1])*fRoot; 1233 | } else { 1234 | // |w| <= 1/2 1235 | var i = 0; 1236 | if ( m[4] > m[0] ) 1237 | i = 1; 1238 | if ( m[8] > m[i*3+i] ) 1239 | i = 2; 1240 | var j = s_iNext[i]; 1241 | var k = s_iNext[j]; 1242 | 1243 | //This isn't quite as clean without array access... 1244 | fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); 1245 | tmp[i] = 0.5 * fRoot; 1246 | 1247 | fRoot = 0.5 / fRoot; 1248 | tmp[j] = (m[j*3+i] + m[i*3+j]) * fRoot; 1249 | tmp[k] = (m[k*3+i] + m[i*3+k]) * fRoot; 1250 | 1251 | this.x = tmp[0]; 1252 | this.y = tmp[1]; 1253 | this.z = tmp[2]; 1254 | this.w = (m[k*3+j] - m[j*3+k]) * fRoot; 1255 | } 1256 | 1257 | return this; 1258 | }; 1259 | 1260 | quat.idt = quat.identity; 1261 | 1262 | quat.sub = quat.subtract; 1263 | 1264 | quat.mul = quat.multiply; 1265 | 1266 | quat.len = quat.length; 1267 | 1268 | quat.lenSq = quat.lengthSq; 1269 | 1270 | //This is handy for Pool utilities, to "reset" a 1271 | //shared object to its default state 1272 | quat.reset = quat.idt; 1273 | 1274 | 1275 | quat.toString = function() { 1276 | return 'Quaternion(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')'; 1277 | }; 1278 | 1279 | quat.str = quat.toString; 1280 | 1281 | module.exports = Quaternion; 1282 | },{"./Matrix3":1,"./Vector3":5,"./common":7}],4:[function(require,module,exports){ 1283 | function Vector2(x, y) { 1284 | if (typeof x === "object") { 1285 | this.x = x.x||0; 1286 | this.y = x.y||0; 1287 | } else { 1288 | this.x = x||0; 1289 | this.y = y||0; 1290 | } 1291 | } 1292 | 1293 | //shorthand it for better minification 1294 | var vec2 = Vector2.prototype; 1295 | 1296 | /** 1297 | * Returns a new instance of Vector2 with 1298 | * this vector's components. 1299 | * @return {Vector2} a clone of this vector 1300 | */ 1301 | vec2.clone = function() { 1302 | return new Vector2(this.x, this.y); 1303 | }; 1304 | 1305 | /** 1306 | * Copies the x, y components from the specified 1307 | * Vector. Any undefined components from `otherVec` 1308 | * will default to zero. 1309 | * 1310 | * @param {otherVec} the other Vector2 to copy 1311 | * @return {Vector2} this, for chaining 1312 | */ 1313 | vec2.copy = function(otherVec) { 1314 | this.x = otherVec.x||0; 1315 | this.y = otherVec.y||0; 1316 | return this; 1317 | }; 1318 | 1319 | /** 1320 | * A convenience function to set the components of 1321 | * this vector as x and y. Falsy or undefined 1322 | * parameters will default to zero. 1323 | * 1324 | * You can also pass a vector object instead of 1325 | * individual components, to copy the object's components. 1326 | * 1327 | * @param {Number} x the x component 1328 | * @param {Number} y the y component 1329 | * @return {Vector2} this, for chaining 1330 | */ 1331 | vec2.set = function(x, y) { 1332 | if (typeof x === "object") { 1333 | this.x = x.x||0; 1334 | this.y = x.y||0; 1335 | } else { 1336 | this.x = x||0; 1337 | this.y = y||0; 1338 | } 1339 | return this; 1340 | }; 1341 | 1342 | vec2.add = function(v) { 1343 | this.x += v.x; 1344 | this.y += v.y; 1345 | return this; 1346 | }; 1347 | 1348 | vec2.subtract = function(v) { 1349 | this.x -= v.x; 1350 | this.y -= v.y; 1351 | return this; 1352 | }; 1353 | 1354 | vec2.multiply = function(v) { 1355 | this.x *= v.x; 1356 | this.y *= v.y; 1357 | return this; 1358 | }; 1359 | 1360 | vec2.scale = function(s) { 1361 | this.x *= s; 1362 | this.y *= s; 1363 | return this; 1364 | }; 1365 | 1366 | vec2.divide = function(v) { 1367 | this.x /= v.x; 1368 | this.y /= v.y; 1369 | return this; 1370 | }; 1371 | 1372 | vec2.negate = function() { 1373 | this.x = -this.x; 1374 | this.y = -this.y; 1375 | return this; 1376 | }; 1377 | 1378 | vec2.distance = function(v) { 1379 | var dx = v.x - this.x, 1380 | dy = v.y - this.y; 1381 | return Math.sqrt(dx*dx + dy*dy); 1382 | }; 1383 | 1384 | vec2.distanceSq = function(v) { 1385 | var dx = v.x - this.x, 1386 | dy = v.y - this.y; 1387 | return dx*dx + dy*dy; 1388 | }; 1389 | 1390 | vec2.length = function() { 1391 | var x = this.x, 1392 | y = this.y; 1393 | return Math.sqrt(x*x + y*y); 1394 | }; 1395 | 1396 | vec2.lengthSq = function() { 1397 | var x = this.x, 1398 | y = this.y; 1399 | return x*x + y*y; 1400 | }; 1401 | 1402 | vec2.normalize = function() { 1403 | var x = this.x, 1404 | y = this.y; 1405 | var len = x*x + y*y; 1406 | if (len > 0) { 1407 | len = 1 / Math.sqrt(len); 1408 | this.x = x*len; 1409 | this.y = y*len; 1410 | } 1411 | return this; 1412 | }; 1413 | 1414 | vec2.dot = function(v) { 1415 | return this.x * v.x + this.y * v.y; 1416 | }; 1417 | 1418 | //Unlike Vector3, this returns a scalar 1419 | //http://allenchou.net/2013/07/cross-product-of-2d-vectors/ 1420 | vec2.cross = function(v) { 1421 | return this.x * v.y - this.y * v.x; 1422 | }; 1423 | 1424 | vec2.lerp = function(v, t) { 1425 | var ax = this.x, 1426 | ay = this.y; 1427 | t = t||0; 1428 | this.x = ax + t * (v.x - ax); 1429 | this.y = ay + t * (v.y - ay); 1430 | return this; 1431 | }; 1432 | 1433 | vec2.transformMat3 = function(mat) { 1434 | var x = this.x, y = this.y, m = mat.val; 1435 | this.x = m[0] * x + m[2] * y + m[4]; 1436 | this.y = m[1] * x + m[3] * y + m[5]; 1437 | return this; 1438 | }; 1439 | 1440 | vec2.transformMat4 = function(mat) { 1441 | var x = this.x, 1442 | y = this.y, 1443 | m = mat.val; 1444 | this.x = m[0] * x + m[4] * y + m[12]; 1445 | this.y = m[1] * x + m[5] * y + m[13]; 1446 | return this; 1447 | }; 1448 | 1449 | vec2.reset = function() { 1450 | this.x = 0; 1451 | this.y = 0; 1452 | return this; 1453 | }; 1454 | 1455 | vec2.sub = vec2.subtract; 1456 | 1457 | vec2.mul = vec2.multiply; 1458 | 1459 | vec2.div = vec2.divide; 1460 | 1461 | vec2.dist = vec2.distance; 1462 | 1463 | vec2.distSq = vec2.distanceSq; 1464 | 1465 | vec2.len = vec2.length; 1466 | 1467 | vec2.lenSq = vec2.lengthSq; 1468 | 1469 | vec2.toString = function() { 1470 | return 'Vector2(' + this.x + ', ' + this.y + ')'; 1471 | }; 1472 | 1473 | vec2.random = function(scale) { 1474 | scale = scale || 1.0; 1475 | var r = Math.random() * 2.0 * Math.PI; 1476 | this.x = Math.cos(r) * scale; 1477 | this.y = Math.sin(r) * scale; 1478 | return this; 1479 | }; 1480 | 1481 | vec2.str = vec2.toString; 1482 | 1483 | module.exports = Vector2; 1484 | },{}],5:[function(require,module,exports){ 1485 | function Vector3(x, y, z) { 1486 | if (typeof x === "object") { 1487 | this.x = x.x||0; 1488 | this.y = x.y||0; 1489 | this.z = x.z||0; 1490 | } else { 1491 | this.x = x||0; 1492 | this.y = y||0; 1493 | this.z = z||0; 1494 | } 1495 | } 1496 | 1497 | //shorthand it for better minification 1498 | var vec3 = Vector3.prototype; 1499 | 1500 | vec3.clone = function() { 1501 | return new Vector3(this.x, this.y, this.z); 1502 | }; 1503 | 1504 | vec3.copy = function(otherVec) { 1505 | this.x = otherVec.x; 1506 | this.y = otherVec.y; 1507 | this.z = otherVec.z; 1508 | return this; 1509 | }; 1510 | 1511 | vec3.set = function(x, y, z) { 1512 | if (typeof x === "object") { 1513 | this.x = x.x||0; 1514 | this.y = x.y||0; 1515 | this.z = x.z||0; 1516 | } else { 1517 | this.x = x||0; 1518 | this.y = y||0; 1519 | this.z = z||0; 1520 | } 1521 | return this; 1522 | }; 1523 | 1524 | vec3.add = function(v) { 1525 | this.x += v.x; 1526 | this.y += v.y; 1527 | this.z += v.z; 1528 | return this; 1529 | }; 1530 | 1531 | vec3.subtract = function(v) { 1532 | this.x -= v.x; 1533 | this.y -= v.y; 1534 | this.z -= v.z; 1535 | return this; 1536 | }; 1537 | 1538 | vec3.multiply = function(v) { 1539 | this.x *= v.x; 1540 | this.y *= v.y; 1541 | this.z *= v.z; 1542 | return this; 1543 | }; 1544 | 1545 | vec3.scale = function(s) { 1546 | this.x *= s; 1547 | this.y *= s; 1548 | this.z *= s; 1549 | return this; 1550 | }; 1551 | 1552 | vec3.divide = function(v) { 1553 | this.x /= v.x; 1554 | this.y /= v.y; 1555 | this.z /= v.z; 1556 | return this; 1557 | }; 1558 | 1559 | vec3.negate = function() { 1560 | this.x = -this.x; 1561 | this.y = -this.y; 1562 | this.z = -this.z; 1563 | return this; 1564 | }; 1565 | 1566 | vec3.distance = function(v) { 1567 | var dx = v.x - this.x, 1568 | dy = v.y - this.y, 1569 | dz = v.z - this.z; 1570 | return Math.sqrt(dx*dx + dy*dy + dz*dz); 1571 | }; 1572 | 1573 | vec3.distanceSq = function(v) { 1574 | var dx = v.x - this.x, 1575 | dy = v.y - this.y, 1576 | dz = v.z - this.z; 1577 | return dx*dx + dy*dy + dz*dz; 1578 | }; 1579 | 1580 | vec3.length = function() { 1581 | var x = this.x, 1582 | y = this.y, 1583 | z = this.z; 1584 | return Math.sqrt(x*x + y*y + z*z); 1585 | }; 1586 | 1587 | vec3.lengthSq = function() { 1588 | var x = this.x, 1589 | y = this.y, 1590 | z = this.z; 1591 | return x*x + y*y + z*z; 1592 | }; 1593 | 1594 | vec3.normalize = function() { 1595 | var x = this.x, 1596 | y = this.y, 1597 | z = this.z; 1598 | var len = x*x + y*y + z*z; 1599 | if (len > 0) { 1600 | len = 1 / Math.sqrt(len); 1601 | this.x = x*len; 1602 | this.y = y*len; 1603 | this.z = z*len; 1604 | } 1605 | return this; 1606 | }; 1607 | 1608 | vec3.dot = function(v) { 1609 | return this.x * v.x + this.y * v.y + this.z * v.z; 1610 | }; 1611 | 1612 | vec3.cross = function(v) { 1613 | var ax = this.x, ay = this.y, az = this.z, 1614 | bx = v.x, by = v.y, bz = v.z; 1615 | 1616 | this.x = ay * bz - az * by; 1617 | this.y = az * bx - ax * bz; 1618 | this.z = ax * by - ay * bx; 1619 | return this; 1620 | }; 1621 | 1622 | vec3.lerp = function(v, t) { 1623 | var ax = this.x, 1624 | ay = this.y, 1625 | az = this.z; 1626 | t = t||0; 1627 | this.x = ax + t * (v.x - ax); 1628 | this.y = ay + t * (v.y - ay); 1629 | this.z = az + t * (v.z - az); 1630 | return this; 1631 | }; 1632 | 1633 | vec3.transformMat4 = function(mat) { 1634 | var x = this.x, y = this.y, z = this.z, m = mat.val; 1635 | this.x = m[0] * x + m[4] * y + m[8] * z + m[12]; 1636 | this.y = m[1] * x + m[5] * y + m[9] * z + m[13]; 1637 | this.z = m[2] * x + m[6] * y + m[10] * z + m[14]; 1638 | return this; 1639 | }; 1640 | 1641 | vec3.transformMat3 = function(mat) { 1642 | var x = this.x, y = this.y, z = this.z, m = mat.val; 1643 | this.x = x * m[0] + y * m[3] + z * m[6]; 1644 | this.y = x * m[1] + y * m[4] + z * m[7]; 1645 | this.z = x * m[2] + y * m[5] + z * m[8]; 1646 | return this; 1647 | }; 1648 | 1649 | vec3.transformQuat = function(q) { 1650 | // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations 1651 | var x = this.x, y = this.y, z = this.z, 1652 | qx = q.x, qy = q.y, qz = q.z, qw = q.w, 1653 | 1654 | // calculate quat * vec 1655 | ix = qw * x + qy * z - qz * y, 1656 | iy = qw * y + qz * x - qx * z, 1657 | iz = qw * z + qx * y - qy * x, 1658 | iw = -qx * x - qy * y - qz * z; 1659 | 1660 | // calculate result * inverse quat 1661 | this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; 1662 | this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; 1663 | this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; 1664 | return this; 1665 | }; 1666 | 1667 | /** 1668 | * Multiplies this Vector3 by the specified matrix, 1669 | * applying a W divide. This is useful for projection, 1670 | * e.g. unprojecting a 2D point into 3D space. 1671 | * 1672 | * @method prj 1673 | * @param {Matrix4} the 4x4 matrix to multiply with 1674 | * @return {Vector3} this object for chaining 1675 | */ 1676 | vec3.project = function(mat) { 1677 | var x = this.x, 1678 | y = this.y, 1679 | z = this.z, 1680 | m = mat.val, 1681 | a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3], 1682 | a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7], 1683 | a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11], 1684 | a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15]; 1685 | 1686 | var l_w = 1 / (x * a03 + y * a13 + z * a23 + a33); 1687 | 1688 | this.x = (x * a00 + y * a10 + z * a20 + a30) * l_w; 1689 | this.y = (x * a01 + y * a11 + z * a21 + a31) * l_w; 1690 | this.z = (x * a02 + y * a12 + z * a22 + a32) * l_w; 1691 | return this; 1692 | }; 1693 | 1694 | /** 1695 | * Unproject this point from 2D space to 3D space. 1696 | * The point should have its x and y properties set to 1697 | * 2D screen space, and the z either at 0 (near plane) 1698 | * or 1 (far plane). The provided matrix is assumed to already 1699 | * be combined, i.e. projection * view * model. 1700 | * 1701 | * After this operation, this vector's (x, y, z) components will 1702 | * represent the unprojected 3D coordinate. 1703 | * 1704 | * @param {Vector4} viewport screen x, y, width and height in pixels 1705 | * @param {Matrix4} invProjectionView combined projection and view matrix 1706 | * @return {Vector3} this object, for chaining 1707 | */ 1708 | vec3.unproject = function(viewport, invProjectionView) { 1709 | var viewX = viewport.x, 1710 | viewY = viewport.y, 1711 | viewWidth = viewport.z, 1712 | viewHeight = viewport.w; 1713 | 1714 | var x = this.x, 1715 | y = this.y, 1716 | z = this.z; 1717 | 1718 | x = x - viewX; 1719 | y = viewHeight - y - 1; 1720 | y = y - viewY; 1721 | 1722 | this.x = (2 * x) / viewWidth - 1; 1723 | this.y = (2 * y) / viewHeight - 1; 1724 | this.z = 2 * z - 1; 1725 | 1726 | return this.project(invProjectionView); 1727 | }; 1728 | 1729 | vec3.random = function(scale) { 1730 | scale = scale || 1.0; 1731 | 1732 | var r = Math.random() * 2.0 * Math.PI; 1733 | var z = (Math.random() * 2.0) - 1.0; 1734 | var zScale = Math.sqrt(1.0-z*z) * scale; 1735 | 1736 | this.x = Math.cos(r) * zScale; 1737 | this.y = Math.sin(r) * zScale; 1738 | this.z = z * scale; 1739 | return this; 1740 | }; 1741 | 1742 | vec3.reset = function() { 1743 | this.x = 0; 1744 | this.y = 0; 1745 | this.z = 0; 1746 | return this; 1747 | }; 1748 | 1749 | 1750 | vec3.sub = vec3.subtract; 1751 | 1752 | vec3.mul = vec3.multiply; 1753 | 1754 | vec3.div = vec3.divide; 1755 | 1756 | vec3.dist = vec3.distance; 1757 | 1758 | vec3.distSq = vec3.distanceSq; 1759 | 1760 | vec3.len = vec3.length; 1761 | 1762 | vec3.lenSq = vec3.lengthSq; 1763 | 1764 | vec3.toString = function() { 1765 | return 'Vector3(' + this.x + ', ' + this.y + ', ' + this.z + ')'; 1766 | }; 1767 | 1768 | vec3.str = vec3.toString; 1769 | 1770 | module.exports = Vector3; 1771 | },{}],6:[function(require,module,exports){ 1772 | var common = require('./common'); 1773 | 1774 | function Vector4(x, y, z, w) { 1775 | if (typeof x === "object") { 1776 | this.x = x.x||0; 1777 | this.y = x.y||0; 1778 | this.z = x.z||0; 1779 | this.w = x.w||0; 1780 | } else { 1781 | this.x = x||0; 1782 | this.y = y||0; 1783 | this.z = z||0; 1784 | this.w = w||0; 1785 | } 1786 | } 1787 | 1788 | //shorthand it for better minification 1789 | var vec4 = Vector4.prototype; 1790 | 1791 | //mixin common functions 1792 | for (var k in common) { 1793 | vec4[k] = common[k]; 1794 | } 1795 | 1796 | vec4.clone = function() { 1797 | return new Vector4(this.x, this.y, this.z, this.w); 1798 | }; 1799 | 1800 | vec4.multiply = function(v) { 1801 | this.x *= v.x; 1802 | this.y *= v.y; 1803 | this.z *= v.z; 1804 | this.w *= v.w; 1805 | return this; 1806 | }; 1807 | 1808 | vec4.divide = function(v) { 1809 | this.x /= v.x; 1810 | this.y /= v.y; 1811 | this.z /= v.z; 1812 | this.w /= v.w; 1813 | return this; 1814 | }; 1815 | 1816 | vec4.distance = function(v) { 1817 | var dx = v.x - this.x, 1818 | dy = v.y - this.y, 1819 | dz = v.z - this.z, 1820 | dw = v.w - this.w; 1821 | return Math.sqrt(dx*dx + dy*dy + dz*dz + dw*dw); 1822 | }; 1823 | 1824 | vec4.distanceSq = function(v) { 1825 | var dx = v.x - this.x, 1826 | dy = v.y - this.y, 1827 | dz = v.z - this.z, 1828 | dw = v.w - this.w; 1829 | return dx*dx + dy*dy + dz*dz + dw*dw; 1830 | }; 1831 | 1832 | vec4.negate = function() { 1833 | this.x = -this.x; 1834 | this.y = -this.y; 1835 | this.z = -this.z; 1836 | this.w = -this.w; 1837 | return this; 1838 | }; 1839 | 1840 | vec4.transformMat4 = function(mat) { 1841 | var m = mat.val, x = this.x, y = this.y, z = this.z, w = this.w; 1842 | this.x = m[0] * x + m[4] * y + m[8] * z + m[12] * w; 1843 | this.y = m[1] * x + m[5] * y + m[9] * z + m[13] * w; 1844 | this.z = m[2] * x + m[6] * y + m[10] * z + m[14] * w; 1845 | this.w = m[3] * x + m[7] * y + m[11] * z + m[15] * w; 1846 | return this; 1847 | }; 1848 | 1849 | //// TODO: is this really the same as Vector3 ?? 1850 | /// Also, what about this: 1851 | /// http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/ 1852 | vec4.transformQuat = function(q) { 1853 | // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations 1854 | var x = this.x, y = this.y, z = this.z, 1855 | qx = q.x, qy = q.y, qz = q.z, qw = q.w, 1856 | 1857 | // calculate quat * vec 1858 | ix = qw * x + qy * z - qz * y, 1859 | iy = qw * y + qz * x - qx * z, 1860 | iz = qw * z + qx * y - qy * x, 1861 | iw = -qx * x - qy * y - qz * z; 1862 | 1863 | // calculate result * inverse quat 1864 | this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; 1865 | this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; 1866 | this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; 1867 | return this; 1868 | }; 1869 | 1870 | vec4.random = function(scale) { 1871 | scale = scale || 1.0; 1872 | 1873 | //Not spherical; should fix this for more uniform distribution 1874 | this.x = (Math.random() * 2 - 1) * scale; 1875 | this.y = (Math.random() * 2 - 1) * scale; 1876 | this.z = (Math.random() * 2 - 1) * scale; 1877 | this.w = (Math.random() * 2 - 1) * scale; 1878 | return this; 1879 | }; 1880 | 1881 | vec4.reset = function() { 1882 | this.x = 0; 1883 | this.y = 0; 1884 | this.z = 0; 1885 | this.w = 0; 1886 | return this; 1887 | }; 1888 | 1889 | vec4.sub = vec4.subtract; 1890 | 1891 | vec4.mul = vec4.multiply; 1892 | 1893 | vec4.div = vec4.divide; 1894 | 1895 | vec4.dist = vec4.distance; 1896 | 1897 | vec4.distSq = vec4.distanceSq; 1898 | 1899 | vec4.len = vec4.length; 1900 | 1901 | vec4.lenSq = vec4.lengthSq; 1902 | 1903 | vec4.toString = function() { 1904 | return 'Vector4(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')'; 1905 | }; 1906 | 1907 | vec4.str = vec4.toString; 1908 | 1909 | module.exports = Vector4; 1910 | },{"./common":7}],7:[function(require,module,exports){ 1911 | //common vec4 functions 1912 | module.exports = { 1913 | 1914 | /** 1915 | * Copies the x, y, z, w components from the specified 1916 | * Vector. Unlike most other operations, this function 1917 | * will default undefined components on `otherVec` to zero. 1918 | * 1919 | * @method copy 1920 | * @param {otherVec} the other Vector4 to copy 1921 | * @return {Vector} this, for chaining 1922 | */ 1923 | 1924 | 1925 | /** 1926 | * A convenience function to set the components of 1927 | * this vector as x, y, z, w. Falsy or undefined 1928 | * parameters will default to zero. 1929 | * 1930 | * You can also pass a vector object instead of 1931 | * individual components, to copy the object's components. 1932 | * 1933 | * @method set 1934 | * @param {Number} x the x component 1935 | * @param {Number} y the y component 1936 | * @param {Number} z the z component 1937 | * @param {Number} w the w component 1938 | * @return {Vector2} this, for chaining 1939 | */ 1940 | 1941 | /** 1942 | * Adds the components of the other Vector4 to 1943 | * this vector. 1944 | * 1945 | * @method add 1946 | * @param {Vector4} otherVec other vector, right operand 1947 | * @return {Vector2} this, for chaining 1948 | */ 1949 | 1950 | /** 1951 | * Subtracts the components of the other Vector4 1952 | * from this vector. Aliased as `sub()` 1953 | * 1954 | * @method subtract 1955 | * @param {Vector4} otherVec other vector, right operand 1956 | * @return {Vector2} this, for chaining 1957 | */ 1958 | 1959 | /** 1960 | * Multiplies the components of this Vector4 1961 | * by a scalar amount. 1962 | * 1963 | * @method scale 1964 | * @param {Number} s the scale to multiply by 1965 | * @return {Vector4} this, for chaining 1966 | */ 1967 | 1968 | /** 1969 | * Returns the magnitude (length) of this vector. 1970 | * 1971 | * Aliased as `len()` 1972 | * 1973 | * @method length 1974 | * @return {Number} the length of this vector 1975 | */ 1976 | 1977 | /** 1978 | * Returns the squared magnitude (length) of this vector. 1979 | * 1980 | * Aliased as `lenSq()` 1981 | * 1982 | * @method lengthSq 1983 | * @return {Number} the squared length of this vector 1984 | */ 1985 | 1986 | /** 1987 | * Normalizes this vector to a unit vector. 1988 | * @method normalize 1989 | * @return {Vector4} this, for chaining 1990 | */ 1991 | 1992 | /** 1993 | * Returns the dot product of this vector 1994 | * and the specified Vector4. 1995 | * 1996 | * @method dot 1997 | * @return {Number} the dot product 1998 | */ 1999 | copy: function(otherVec) { 2000 | this.x = otherVec.x||0; 2001 | this.y = otherVec.y||0; 2002 | this.z = otherVec.z||0; 2003 | this.w = otherVec.w||0; 2004 | return this; 2005 | }, 2006 | 2007 | set: function(x, y, z, w) { 2008 | if (typeof x === "object") { 2009 | this.x = x.x||0; 2010 | this.y = x.y||0; 2011 | this.z = x.z||0; 2012 | this.w = x.w||0; 2013 | } else { 2014 | this.x = x||0; 2015 | this.y = y||0; 2016 | this.z = z||0; 2017 | this.w = w||0; 2018 | 2019 | } 2020 | return this; 2021 | }, 2022 | 2023 | add: function(v) { 2024 | this.x += v.x; 2025 | this.y += v.y; 2026 | this.z += v.z; 2027 | this.w += v.w; 2028 | return this; 2029 | }, 2030 | 2031 | subtract: function(v) { 2032 | this.x -= v.x; 2033 | this.y -= v.y; 2034 | this.z -= v.z; 2035 | this.w -= v.w; 2036 | return this; 2037 | }, 2038 | 2039 | scale: function(s) { 2040 | this.x *= s; 2041 | this.y *= s; 2042 | this.z *= s; 2043 | this.w *= s; 2044 | return this; 2045 | }, 2046 | 2047 | 2048 | length: function() { 2049 | var x = this.x, 2050 | y = this.y, 2051 | z = this.z, 2052 | w = this.w; 2053 | return Math.sqrt(x*x + y*y + z*z + w*w); 2054 | }, 2055 | 2056 | lengthSq: function() { 2057 | var x = this.x, 2058 | y = this.y, 2059 | z = this.z, 2060 | w = this.w; 2061 | return x*x + y*y + z*z + w*w; 2062 | }, 2063 | 2064 | normalize: function() { 2065 | var x = this.x, 2066 | y = this.y, 2067 | z = this.z, 2068 | w = this.w; 2069 | var len = x*x + y*y + z*z + w*w; 2070 | if (len > 0) { 2071 | len = 1 / Math.sqrt(len); 2072 | this.x = x*len; 2073 | this.y = y*len; 2074 | this.z = z*len; 2075 | this.w = w*len; 2076 | } 2077 | return this; 2078 | }, 2079 | 2080 | dot: function(v) { 2081 | return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 2082 | }, 2083 | 2084 | lerp: function(v, t) { 2085 | var ax = this.x, 2086 | ay = this.y, 2087 | az = this.z, 2088 | aw = this.w; 2089 | t = t||0; 2090 | this.x = ax + t * (v.x - ax); 2091 | this.y = ay + t * (v.y - ay); 2092 | this.z = az + t * (v.z - az); 2093 | this.w = aw + t * (v.w - aw); 2094 | return this; 2095 | } 2096 | }; 2097 | },{}],8:[function(require,module,exports){ 2098 | module.exports = { 2099 | Vector2: require('./Vector2'), 2100 | Vector3: require('./Vector3'), 2101 | Vector4: require('./Vector4'), 2102 | Matrix3: require('./Matrix3'), 2103 | Matrix4: require('./Matrix4'), 2104 | Quaternion: require('./Quaternion') 2105 | }; 2106 | },{"./Matrix3":1,"./Matrix4":2,"./Quaternion":3,"./Vector2":4,"./Vector3":5,"./Vector4":6}]},{},[8]) 2107 | (8) 2108 | }); 2109 | ; -------------------------------------------------------------------------------- /build/vecmath.min.js: -------------------------------------------------------------------------------- 1 | !function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.vecmath=e():"undefined"!=typeof global?global.vecmath=e():"undefined"!=typeof self&&(self.vecmath=e())}(function(){var define,module,exports;return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o.999999){this.x=0;this.y=0;this.z=0;this.w=1;return this}else{tmpvec.copy(a).cross(b);this.x=tmpvec.x;this.y=tmpvec.y;this.z=tmpvec.z;this.w=1+dot;return this.normalize()}};quat.setAxes=function(view,right,up){var m=tmpMat3.val;m[0]=right.x;m[3]=right.y;m[6]=right.z;m[1]=up.x;m[4]=up.y;m[7]=up.z;m[2]=-view.x;m[5]=-view.y;m[8]=-view.z;return this.fromMat3(tmpMat3).normalize()};quat.identity=function(){this.x=this.y=this.z=0;this.w=1;return this};quat.setAxisAngle=function(axis,rad){rad=rad*.5;var s=Math.sin(rad);this.x=s*axis.x;this.y=s*axis.y;this.z=s*axis.z;this.w=Math.cos(rad);return this};quat.multiply=function(b){var ax=this.x,ay=this.y,az=this.z,aw=this.w,bx=b.x,by=b.y,bz=b.z,bw=b.w;this.x=ax*bw+aw*bx+ay*bz-az*by;this.y=ay*bw+aw*by+az*bx-ax*bz;this.z=az*bw+aw*bz+ax*by-ay*bx;this.w=aw*bw-ax*bx-ay*by-az*bz;return this};quat.slerp=function(b,t){var ax=this.x,ay=this.y,az=this.y,aw=this.y,bx=b.x,by=b.y,bz=b.z,bw=b.w;var omega,cosom,sinom,scale0,scale1;cosom=ax*bx+ay*by+az*bz+aw*bw;if(cosom<0){cosom=-cosom;bx=-bx;by=-by;bz=-bz;bw=-bw}if(1-cosom>1e-6){omega=Math.acos(cosom);sinom=Math.sin(omega);scale0=Math.sin((1-t)*omega)/sinom;scale1=Math.sin(t*omega)/sinom}else{scale0=1-t;scale1=t}this.x=scale0*ax+scale1*bx;this.y=scale0*ay+scale1*by;this.z=scale0*az+scale1*bz;this.w=scale0*aw+scale1*bw;return this};quat.invert=function(){var a0=this.x,a1=this.y,a2=this.z,a3=this.w,dot=a0*a0+a1*a1+a2*a2+a3*a3,invDot=dot?1/dot:0;this.x=-a0*invDot;this.y=-a1*invDot;this.z=-a2*invDot;this.w=a3*invDot;return this};quat.conjugate=function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this};quat.rotateX=function(rad){rad*=.5;var ax=this.x,ay=this.y,az=this.z,aw=this.w,bx=Math.sin(rad),bw=Math.cos(rad);this.x=ax*bw+aw*bx;this.y=ay*bw+az*bx;this.z=az*bw-ay*bx;this.w=aw*bw-ax*bx;return this};quat.rotateY=function(rad){rad*=.5;var ax=this.x,ay=this.y,az=this.z,aw=this.w,by=Math.sin(rad),bw=Math.cos(rad);this.x=ax*bw-az*by;this.y=ay*bw+aw*by;this.z=az*bw+ax*by;this.w=aw*bw-ay*by;return this};quat.rotateZ=function(rad){rad*=.5;var ax=this.x,ay=this.y,az=this.z,aw=this.w,bz=Math.sin(rad),bw=Math.cos(rad);this.x=ax*bw+ay*bz;this.y=ay*bw-ax*bz;this.z=az*bw+aw*bz;this.w=aw*bw-az*bz;return this};quat.calculateW=function(){var x=this.x,y=this.y,z=this.z;this.x=x;this.y=y;this.z=z;this.w=-Math.sqrt(Math.abs(1-x*x-y*y-z*z));return this};quat.fromMat3=function(mat){var m=mat.val,fTrace=m[0]+m[4]+m[8];var fRoot;if(fTrace>0){fRoot=Math.sqrt(fTrace+1);this.w=.5*fRoot;fRoot=.5/fRoot;this.x=(m[7]-m[5])*fRoot;this.y=(m[2]-m[6])*fRoot;this.z=(m[3]-m[1])*fRoot}else{var i=0;if(m[4]>m[0])i=1;if(m[8]>m[i*3+i])i=2;var j=s_iNext[i];var k=s_iNext[j];fRoot=Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k]+1);tmp[i]=.5*fRoot;fRoot=.5/fRoot;tmp[j]=(m[j*3+i]+m[i*3+j])*fRoot;tmp[k]=(m[k*3+i]+m[i*3+k])*fRoot;this.x=tmp[0];this.y=tmp[1];this.z=tmp[2];this.w=(m[k*3+j]-m[j*3+k])*fRoot}return this};quat.idt=quat.identity;quat.sub=quat.subtract;quat.mul=quat.multiply;quat.len=quat.length;quat.lenSq=quat.lengthSq;quat.reset=quat.idt;quat.toString=function(){return"Quaternion("+this.x+", "+this.y+", "+this.z+", "+this.w+")"};quat.str=quat.toString;module.exports=Quaternion},{"./Matrix3":1,"./Vector3":5,"./common":7}],4:[function(require,module,exports){function Vector2(x,y){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0}else{this.x=x||0;this.y=y||0}}var vec2=Vector2.prototype;vec2.clone=function(){return new Vector2(this.x,this.y)};vec2.copy=function(otherVec){this.x=otherVec.x||0;this.y=otherVec.y||0;return this};vec2.set=function(x,y){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0}else{this.x=x||0;this.y=y||0}return this};vec2.add=function(v){this.x+=v.x;this.y+=v.y;return this};vec2.subtract=function(v){this.x-=v.x;this.y-=v.y;return this};vec2.multiply=function(v){this.x*=v.x;this.y*=v.y;return this};vec2.scale=function(s){this.x*=s;this.y*=s;return this};vec2.divide=function(v){this.x/=v.x;this.y/=v.y;return this};vec2.negate=function(){this.x=-this.x;this.y=-this.y;return this};vec2.distance=function(v){var dx=v.x-this.x,dy=v.y-this.y;return Math.sqrt(dx*dx+dy*dy)};vec2.distanceSq=function(v){var dx=v.x-this.x,dy=v.y-this.y;return dx*dx+dy*dy};vec2.length=function(){var x=this.x,y=this.y;return Math.sqrt(x*x+y*y)};vec2.lengthSq=function(){var x=this.x,y=this.y;return x*x+y*y};vec2.normalize=function(){var x=this.x,y=this.y;var len=x*x+y*y;if(len>0){len=1/Math.sqrt(len);this.x=x*len;this.y=y*len}return this};vec2.dot=function(v){return this.x*v.x+this.y*v.y};vec2.cross=function(v){return this.x*v.y-this.y*v.x};vec2.lerp=function(v,t){var ax=this.x,ay=this.y;t=t||0;this.x=ax+t*(v.x-ax);this.y=ay+t*(v.y-ay);return this};vec2.transformMat3=function(mat){var x=this.x,y=this.y,m=mat.val;this.x=m[0]*x+m[2]*y+m[4];this.y=m[1]*x+m[3]*y+m[5];return this};vec2.transformMat4=function(mat){var x=this.x,y=this.y,m=mat.val;this.x=m[0]*x+m[4]*y+m[12];this.y=m[1]*x+m[5]*y+m[13];return this};vec2.reset=function(){this.x=0;this.y=0;return this};vec2.sub=vec2.subtract;vec2.mul=vec2.multiply;vec2.div=vec2.divide;vec2.dist=vec2.distance;vec2.distSq=vec2.distanceSq;vec2.len=vec2.length;vec2.lenSq=vec2.lengthSq;vec2.toString=function(){return"Vector2("+this.x+", "+this.y+")"};vec2.random=function(scale){scale=scale||1;var r=Math.random()*2*Math.PI;this.x=Math.cos(r)*scale;this.y=Math.sin(r)*scale;return this};vec2.str=vec2.toString;module.exports=Vector2},{}],5:[function(require,module,exports){function Vector3(x,y,z){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0;this.z=x.z||0}else{this.x=x||0;this.y=y||0;this.z=z||0}}var vec3=Vector3.prototype;vec3.clone=function(){return new Vector3(this.x,this.y,this.z)};vec3.copy=function(otherVec){this.x=otherVec.x;this.y=otherVec.y;this.z=otherVec.z;return this};vec3.set=function(x,y,z){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0;this.z=x.z||0}else{this.x=x||0;this.y=y||0;this.z=z||0}return this};vec3.add=function(v){this.x+=v.x;this.y+=v.y;this.z+=v.z;return this};vec3.subtract=function(v){this.x-=v.x;this.y-=v.y;this.z-=v.z;return this};vec3.multiply=function(v){this.x*=v.x;this.y*=v.y;this.z*=v.z;return this};vec3.scale=function(s){this.x*=s;this.y*=s;this.z*=s;return this};vec3.divide=function(v){this.x/=v.x;this.y/=v.y;this.z/=v.z;return this};vec3.negate=function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this};vec3.distance=function(v){var dx=v.x-this.x,dy=v.y-this.y,dz=v.z-this.z;return Math.sqrt(dx*dx+dy*dy+dz*dz)};vec3.distanceSq=function(v){var dx=v.x-this.x,dy=v.y-this.y,dz=v.z-this.z;return dx*dx+dy*dy+dz*dz};vec3.length=function(){var x=this.x,y=this.y,z=this.z;return Math.sqrt(x*x+y*y+z*z)};vec3.lengthSq=function(){var x=this.x,y=this.y,z=this.z;return x*x+y*y+z*z};vec3.normalize=function(){var x=this.x,y=this.y,z=this.z;var len=x*x+y*y+z*z;if(len>0){len=1/Math.sqrt(len);this.x=x*len;this.y=y*len;this.z=z*len}return this};vec3.dot=function(v){return this.x*v.x+this.y*v.y+this.z*v.z};vec3.cross=function(v){var ax=this.x,ay=this.y,az=this.z,bx=v.x,by=v.y,bz=v.z;this.x=ay*bz-az*by;this.y=az*bx-ax*bz;this.z=ax*by-ay*bx;return this};vec3.lerp=function(v,t){var ax=this.x,ay=this.y,az=this.z;t=t||0;this.x=ax+t*(v.x-ax);this.y=ay+t*(v.y-ay);this.z=az+t*(v.z-az);return this};vec3.transformMat4=function(mat){var x=this.x,y=this.y,z=this.z,m=mat.val;this.x=m[0]*x+m[4]*y+m[8]*z+m[12];this.y=m[1]*x+m[5]*y+m[9]*z+m[13];this.z=m[2]*x+m[6]*y+m[10]*z+m[14];return this};vec3.transformMat3=function(mat){var x=this.x,y=this.y,z=this.z,m=mat.val;this.x=x*m[0]+y*m[3]+z*m[6];this.y=x*m[1]+y*m[4]+z*m[7];this.z=x*m[2]+y*m[5]+z*m[8];return this};vec3.transformQuat=function(q){var x=this.x,y=this.y,z=this.z,qx=q.x,qy=q.y,qz=q.z,qw=q.w,ix=qw*x+qy*z-qz*y,iy=qw*y+qz*x-qx*z,iz=qw*z+qx*y-qy*x,iw=-qx*x-qy*y-qz*z;this.x=ix*qw+iw*-qx+iy*-qz-iz*-qy;this.y=iy*qw+iw*-qy+iz*-qx-ix*-qz;this.z=iz*qw+iw*-qz+ix*-qy-iy*-qx;return this};vec3.project=function(mat){var x=this.x,y=this.y,z=this.z,m=mat.val,a00=m[0],a01=m[1],a02=m[2],a03=m[3],a10=m[4],a11=m[5],a12=m[6],a13=m[7],a20=m[8],a21=m[9],a22=m[10],a23=m[11],a30=m[12],a31=m[13],a32=m[14],a33=m[15];var l_w=1/(x*a03+y*a13+z*a23+a33);this.x=(x*a00+y*a10+z*a20+a30)*l_w;this.y=(x*a01+y*a11+z*a21+a31)*l_w;this.z=(x*a02+y*a12+z*a22+a32)*l_w;return this};vec3.unproject=function(viewport,invProjectionView){var viewX=viewport.x,viewY=viewport.y,viewWidth=viewport.z,viewHeight=viewport.w;var x=this.x,y=this.y,z=this.z;x=x-viewX;y=viewHeight-y-1;y=y-viewY;this.x=2*x/viewWidth-1;this.y=2*y/viewHeight-1;this.z=2*z-1;return this.project(invProjectionView)};vec3.random=function(scale){scale=scale||1;var r=Math.random()*2*Math.PI;var z=Math.random()*2-1;var zScale=Math.sqrt(1-z*z)*scale;this.x=Math.cos(r)*zScale;this.y=Math.sin(r)*zScale;this.z=z*scale;return this};vec3.reset=function(){this.x=0;this.y=0;this.z=0;return this};vec3.sub=vec3.subtract;vec3.mul=vec3.multiply;vec3.div=vec3.divide;vec3.dist=vec3.distance;vec3.distSq=vec3.distanceSq;vec3.len=vec3.length;vec3.lenSq=vec3.lengthSq;vec3.toString=function(){return"Vector3("+this.x+", "+this.y+", "+this.z+")"};vec3.str=vec3.toString;module.exports=Vector3},{}],6:[function(require,module,exports){var common=require("./common");function Vector4(x,y,z,w){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0;this.z=x.z||0;this.w=x.w||0}else{this.x=x||0;this.y=y||0;this.z=z||0;this.w=w||0}}var vec4=Vector4.prototype;for(var k in common){vec4[k]=common[k]}vec4.clone=function(){return new Vector4(this.x,this.y,this.z,this.w)};vec4.multiply=function(v){this.x*=v.x;this.y*=v.y;this.z*=v.z;this.w*=v.w;return this};vec4.divide=function(v){this.x/=v.x;this.y/=v.y;this.z/=v.z;this.w/=v.w;return this};vec4.distance=function(v){var dx=v.x-this.x,dy=v.y-this.y,dz=v.z-this.z,dw=v.w-this.w;return Math.sqrt(dx*dx+dy*dy+dz*dz+dw*dw)};vec4.distanceSq=function(v){var dx=v.x-this.x,dy=v.y-this.y,dz=v.z-this.z,dw=v.w-this.w;return dx*dx+dy*dy+dz*dz+dw*dw};vec4.negate=function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this};vec4.transformMat4=function(mat){var m=mat.val,x=this.x,y=this.y,z=this.z,w=this.w;this.x=m[0]*x+m[4]*y+m[8]*z+m[12]*w;this.y=m[1]*x+m[5]*y+m[9]*z+m[13]*w;this.z=m[2]*x+m[6]*y+m[10]*z+m[14]*w;this.w=m[3]*x+m[7]*y+m[11]*z+m[15]*w;return this};vec4.transformQuat=function(q){var x=this.x,y=this.y,z=this.z,qx=q.x,qy=q.y,qz=q.z,qw=q.w,ix=qw*x+qy*z-qz*y,iy=qw*y+qz*x-qx*z,iz=qw*z+qx*y-qy*x,iw=-qx*x-qy*y-qz*z;this.x=ix*qw+iw*-qx+iy*-qz-iz*-qy;this.y=iy*qw+iw*-qy+iz*-qx-ix*-qz;this.z=iz*qw+iw*-qz+ix*-qy-iy*-qx;return this};vec4.random=function(scale){scale=scale||1;this.x=(Math.random()*2-1)*scale;this.y=(Math.random()*2-1)*scale;this.z=(Math.random()*2-1)*scale;this.w=(Math.random()*2-1)*scale;return this};vec4.reset=function(){this.x=0;this.y=0;this.z=0;this.w=0;return this};vec4.sub=vec4.subtract;vec4.mul=vec4.multiply;vec4.div=vec4.divide;vec4.dist=vec4.distance;vec4.distSq=vec4.distanceSq;vec4.len=vec4.length;vec4.lenSq=vec4.lengthSq;vec4.toString=function(){return"Vector4("+this.x+", "+this.y+", "+this.z+", "+this.w+")"};vec4.str=vec4.toString;module.exports=Vector4},{"./common":7}],7:[function(require,module,exports){module.exports={copy:function(otherVec){this.x=otherVec.x||0;this.y=otherVec.y||0;this.z=otherVec.z||0;this.w=otherVec.w||0;return this},set:function(x,y,z,w){if(typeof x==="object"){this.x=x.x||0;this.y=x.y||0;this.z=x.z||0;this.w=x.w||0}else{this.x=x||0;this.y=y||0;this.z=z||0;this.w=w||0}return this},add:function(v){this.x+=v.x;this.y+=v.y;this.z+=v.z;this.w+=v.w;return this},subtract:function(v){this.x-=v.x;this.y-=v.y;this.z-=v.z;this.w-=v.w;return this},scale:function(s){this.x*=s;this.y*=s;this.z*=s;this.w*=s;return this},length:function(){var x=this.x,y=this.y,z=this.z,w=this.w;return Math.sqrt(x*x+y*y+z*z+w*w)},lengthSq:function(){var x=this.x,y=this.y,z=this.z,w=this.w;return x*x+y*y+z*z+w*w},normalize:function(){var x=this.x,y=this.y,z=this.z,w=this.w;var len=x*x+y*y+z*z+w*w;if(len>0){len=1/Math.sqrt(len);this.x=x*len;this.y=y*len;this.z=z*len;this.w=w*len}return this},dot:function(v){return this.x*v.x+this.y*v.y+this.z*v.z+this.w*v.w},lerp:function(v,t){var ax=this.x,ay=this.y,az=this.z,aw=this.w;t=t||0;this.x=ax+t*(v.x-ax);this.y=ay+t*(v.y-ay);this.z=az+t*(v.z-az);this.w=aw+t*(v.w-aw);return this}}},{}],8:[function(require,module,exports){module.exports={Vector2:require("./Vector2"),Vector3:require("./Vector3"),Vector4:require("./Vector4"),Matrix3:require("./Matrix3"),Matrix4:require("./Matrix4"),Quaternion:require("./Quaternion")}},{"./Matrix3":1,"./Matrix4":2,"./Quaternion":3,"./Vector2":4,"./Vector3":5,"./Vector4":6}]},{},[8])(8)}); -------------------------------------------------------------------------------- /lib/Matrix3.js: -------------------------------------------------------------------------------- 1 | var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array; 2 | 3 | function Matrix3(m) { 4 | this.val = new ARRAY_TYPE(9); 5 | 6 | if (m) { //assume Matrix3 with val 7 | this.copy(m); 8 | } else { //default to identity 9 | this.idt(); 10 | } 11 | } 12 | 13 | var mat3 = Matrix3.prototype; 14 | 15 | mat3.clone = function() { 16 | return new Matrix3(this); 17 | }; 18 | 19 | mat3.set = function(otherMat) { 20 | return this.copy(otherMat); 21 | }; 22 | 23 | mat3.copy = function(otherMat) { 24 | var out = this.val, 25 | a = otherMat.val; 26 | out[0] = a[0]; 27 | out[1] = a[1]; 28 | out[2] = a[2]; 29 | out[3] = a[3]; 30 | out[4] = a[4]; 31 | out[5] = a[5]; 32 | out[6] = a[6]; 33 | out[7] = a[7]; 34 | out[8] = a[8]; 35 | return this; 36 | }; 37 | 38 | mat3.fromMat4 = function(m) { 39 | var a = m.val, 40 | out = this.val; 41 | out[0] = a[0]; 42 | out[1] = a[1]; 43 | out[2] = a[2]; 44 | out[3] = a[4]; 45 | out[4] = a[5]; 46 | out[5] = a[6]; 47 | out[6] = a[8]; 48 | out[7] = a[9]; 49 | out[8] = a[10]; 50 | return this; 51 | }; 52 | 53 | mat3.fromArray = function(a) { 54 | var out = this.val; 55 | out[0] = a[0]; 56 | out[1] = a[1]; 57 | out[2] = a[2]; 58 | out[3] = a[3]; 59 | out[4] = a[4]; 60 | out[5] = a[5]; 61 | out[6] = a[6]; 62 | out[7] = a[7]; 63 | out[8] = a[8]; 64 | return this; 65 | }; 66 | 67 | mat3.identity = function() { 68 | var out = this.val; 69 | out[0] = 1; 70 | out[1] = 0; 71 | out[2] = 0; 72 | out[3] = 0; 73 | out[4] = 1; 74 | out[5] = 0; 75 | out[6] = 0; 76 | out[7] = 0; 77 | out[8] = 1; 78 | return this; 79 | }; 80 | 81 | mat3.transpose = function() { 82 | var a = this.val, 83 | a01 = a[1], 84 | a02 = a[2], 85 | a12 = a[5]; 86 | a[1] = a[3]; 87 | a[2] = a[6]; 88 | a[3] = a01; 89 | a[5] = a[7]; 90 | a[6] = a02; 91 | a[7] = a12; 92 | return this; 93 | }; 94 | 95 | mat3.invert = function() { 96 | var a = this.val, 97 | a00 = a[0], a01 = a[1], a02 = a[2], 98 | a10 = a[3], a11 = a[4], a12 = a[5], 99 | a20 = a[6], a21 = a[7], a22 = a[8], 100 | 101 | b01 = a22 * a11 - a12 * a21, 102 | b11 = -a22 * a10 + a12 * a20, 103 | b21 = a21 * a10 - a11 * a20, 104 | 105 | // Calculate the determinant 106 | det = a00 * b01 + a01 * b11 + a02 * b21; 107 | 108 | if (!det) { 109 | return null; 110 | } 111 | det = 1.0 / det; 112 | 113 | a[0] = b01 * det; 114 | a[1] = (-a22 * a01 + a02 * a21) * det; 115 | a[2] = (a12 * a01 - a02 * a11) * det; 116 | a[3] = b11 * det; 117 | a[4] = (a22 * a00 - a02 * a20) * det; 118 | a[5] = (-a12 * a00 + a02 * a10) * det; 119 | a[6] = b21 * det; 120 | a[7] = (-a21 * a00 + a01 * a20) * det; 121 | a[8] = (a11 * a00 - a01 * a10) * det; 122 | return this; 123 | }; 124 | 125 | mat3.adjoint = function() { 126 | var a = this.val, 127 | a00 = a[0], a01 = a[1], a02 = a[2], 128 | a10 = a[3], a11 = a[4], a12 = a[5], 129 | a20 = a[6], a21 = a[7], a22 = a[8]; 130 | 131 | a[0] = (a11 * a22 - a12 * a21); 132 | a[1] = (a02 * a21 - a01 * a22); 133 | a[2] = (a01 * a12 - a02 * a11); 134 | a[3] = (a12 * a20 - a10 * a22); 135 | a[4] = (a00 * a22 - a02 * a20); 136 | a[5] = (a02 * a10 - a00 * a12); 137 | a[6] = (a10 * a21 - a11 * a20); 138 | a[7] = (a01 * a20 - a00 * a21); 139 | a[8] = (a00 * a11 - a01 * a10); 140 | return this; 141 | }; 142 | 143 | mat3.determinant = function() { 144 | var a = this.val, 145 | a00 = a[0], a01 = a[1], a02 = a[2], 146 | a10 = a[3], a11 = a[4], a12 = a[5], 147 | a20 = a[6], a21 = a[7], a22 = a[8]; 148 | 149 | return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); 150 | }; 151 | 152 | mat3.multiply = function(otherMat) { 153 | var a = this.val, 154 | b = otherMat.val, 155 | a00 = a[0], a01 = a[1], a02 = a[2], 156 | a10 = a[3], a11 = a[4], a12 = a[5], 157 | a20 = a[6], a21 = a[7], a22 = a[8], 158 | 159 | b00 = b[0], b01 = b[1], b02 = b[2], 160 | b10 = b[3], b11 = b[4], b12 = b[5], 161 | b20 = b[6], b21 = b[7], b22 = b[8]; 162 | 163 | a[0] = b00 * a00 + b01 * a10 + b02 * a20; 164 | a[1] = b00 * a01 + b01 * a11 + b02 * a21; 165 | a[2] = b00 * a02 + b01 * a12 + b02 * a22; 166 | 167 | a[3] = b10 * a00 + b11 * a10 + b12 * a20; 168 | a[4] = b10 * a01 + b11 * a11 + b12 * a21; 169 | a[5] = b10 * a02 + b11 * a12 + b12 * a22; 170 | 171 | a[6] = b20 * a00 + b21 * a10 + b22 * a20; 172 | a[7] = b20 * a01 + b21 * a11 + b22 * a21; 173 | a[8] = b20 * a02 + b21 * a12 + b22 * a22; 174 | return this; 175 | }; 176 | 177 | mat3.translate = function(v) { 178 | var a = this.val, 179 | x = v.x, y = v.y; 180 | a[6] = x * a[0] + y * a[3] + a[6]; 181 | a[7] = x * a[1] + y * a[4] + a[7]; 182 | a[8] = x * a[2] + y * a[5] + a[8]; 183 | return this; 184 | }; 185 | 186 | mat3.rotate = function(rad) { 187 | var a = this.val, 188 | a00 = a[0], a01 = a[1], a02 = a[2], 189 | a10 = a[3], a11 = a[4], a12 = a[5], 190 | 191 | s = Math.sin(rad), 192 | c = Math.cos(rad); 193 | 194 | a[0] = c * a00 + s * a10; 195 | a[1] = c * a01 + s * a11; 196 | a[2] = c * a02 + s * a12; 197 | 198 | a[3] = c * a10 - s * a00; 199 | a[4] = c * a11 - s * a01; 200 | a[5] = c * a12 - s * a02; 201 | return this; 202 | }; 203 | 204 | mat3.scale = function(v) { 205 | var a = this.val, 206 | x = v.x, 207 | y = v.y; 208 | 209 | a[0] = x * a[0]; 210 | a[1] = x * a[1]; 211 | a[2] = x * a[2]; 212 | 213 | a[3] = y * a[3]; 214 | a[4] = y * a[4]; 215 | a[5] = y * a[5]; 216 | return this; 217 | }; 218 | 219 | mat3.fromQuat = function(q) { 220 | var x = q.x, y = q.y, z = q.z, w = q.w, 221 | x2 = x + x, 222 | y2 = y + y, 223 | z2 = z + z, 224 | 225 | xx = x * x2, 226 | xy = x * y2, 227 | xz = x * z2, 228 | yy = y * y2, 229 | yz = y * z2, 230 | zz = z * z2, 231 | wx = w * x2, 232 | wy = w * y2, 233 | wz = w * z2, 234 | 235 | out = this.val; 236 | 237 | out[0] = 1 - (yy + zz); 238 | out[3] = xy + wz; 239 | out[6] = xz - wy; 240 | 241 | out[1] = xy - wz; 242 | out[4] = 1 - (xx + zz); 243 | out[7] = yz + wx; 244 | 245 | out[2] = xz + wy; 246 | out[5] = yz - wx; 247 | out[8] = 1 - (xx + yy); 248 | return this; 249 | }; 250 | 251 | mat3.normalFromMat4 = function(m) { 252 | var a = m.val, 253 | out = this.val, 254 | 255 | a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 256 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 257 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 258 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], 259 | 260 | b00 = a00 * a11 - a01 * a10, 261 | b01 = a00 * a12 - a02 * a10, 262 | b02 = a00 * a13 - a03 * a10, 263 | b03 = a01 * a12 - a02 * a11, 264 | b04 = a01 * a13 - a03 * a11, 265 | b05 = a02 * a13 - a03 * a12, 266 | b06 = a20 * a31 - a21 * a30, 267 | b07 = a20 * a32 - a22 * a30, 268 | b08 = a20 * a33 - a23 * a30, 269 | b09 = a21 * a32 - a22 * a31, 270 | b10 = a21 * a33 - a23 * a31, 271 | b11 = a22 * a33 - a23 * a32, 272 | 273 | // Calculate the determinant 274 | det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; 275 | 276 | if (!det) { 277 | return null; 278 | } 279 | det = 1.0 / det; 280 | 281 | out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; 282 | out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; 283 | out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; 284 | 285 | out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; 286 | out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; 287 | out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; 288 | 289 | out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; 290 | out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; 291 | out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; 292 | return this; 293 | }; 294 | 295 | mat3.mul = mat3.multiply; 296 | 297 | mat3.idt = mat3.identity; 298 | 299 | //This is handy for Pool utilities, to "reset" a 300 | //shared object to its default state 301 | mat3.reset = mat3.idt; 302 | 303 | mat3.toString = function() { 304 | var a = this.val; 305 | return 'Matrix3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + 306 | a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + 307 | a[6] + ', ' + a[7] + ', ' + a[8] + ')'; 308 | }; 309 | 310 | mat3.str = mat3.toString; 311 | 312 | module.exports = Matrix3; -------------------------------------------------------------------------------- /lib/Matrix4.js: -------------------------------------------------------------------------------- 1 | var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array; 2 | var EPSILON = 0.000001; 3 | 4 | function Matrix4(m) { 5 | this.val = new ARRAY_TYPE(16); 6 | 7 | if (m) { //assume Matrix4 with val 8 | this.copy(m); 9 | } else { //default to identity 10 | this.idt(); 11 | } 12 | } 13 | 14 | var mat4 = Matrix4.prototype; 15 | 16 | mat4.clone = function() { 17 | return new Matrix4(this); 18 | }; 19 | 20 | mat4.set = function(otherMat) { 21 | return this.copy(otherMat); 22 | }; 23 | 24 | mat4.copy = function(otherMat) { 25 | var out = this.val, 26 | a = otherMat.val; 27 | out[0] = a[0]; 28 | out[1] = a[1]; 29 | out[2] = a[2]; 30 | out[3] = a[3]; 31 | out[4] = a[4]; 32 | out[5] = a[5]; 33 | out[6] = a[6]; 34 | out[7] = a[7]; 35 | out[8] = a[8]; 36 | out[9] = a[9]; 37 | out[10] = a[10]; 38 | out[11] = a[11]; 39 | out[12] = a[12]; 40 | out[13] = a[13]; 41 | out[14] = a[14]; 42 | out[15] = a[15]; 43 | return this; 44 | }; 45 | 46 | mat4.fromArray = function(a) { 47 | var out = this.val; 48 | out[0] = a[0]; 49 | out[1] = a[1]; 50 | out[2] = a[2]; 51 | out[3] = a[3]; 52 | out[4] = a[4]; 53 | out[5] = a[5]; 54 | out[6] = a[6]; 55 | out[7] = a[7]; 56 | out[8] = a[8]; 57 | out[9] = a[9]; 58 | out[10] = a[10]; 59 | out[11] = a[11]; 60 | out[12] = a[12]; 61 | out[13] = a[13]; 62 | out[14] = a[14]; 63 | out[15] = a[15]; 64 | return this; 65 | }; 66 | 67 | mat4.identity = function() { 68 | var out = this.val; 69 | out[0] = 1; 70 | out[1] = 0; 71 | out[2] = 0; 72 | out[3] = 0; 73 | out[4] = 0; 74 | out[5] = 1; 75 | out[6] = 0; 76 | out[7] = 0; 77 | out[8] = 0; 78 | out[9] = 0; 79 | out[10] = 1; 80 | out[11] = 0; 81 | out[12] = 0; 82 | out[13] = 0; 83 | out[14] = 0; 84 | out[15] = 1; 85 | return this; 86 | }; 87 | 88 | mat4.transpose = function() { 89 | var a = this.val, 90 | a01 = a[1], a02 = a[2], a03 = a[3], 91 | a12 = a[6], a13 = a[7], 92 | a23 = a[11]; 93 | 94 | a[1] = a[4]; 95 | a[2] = a[8]; 96 | a[3] = a[12]; 97 | a[4] = a01; 98 | a[6] = a[9]; 99 | a[7] = a[13]; 100 | a[8] = a02; 101 | a[9] = a12; 102 | a[11] = a[14]; 103 | a[12] = a03; 104 | a[13] = a13; 105 | a[14] = a23; 106 | return this; 107 | }; 108 | 109 | mat4.invert = function() { 110 | var a = this.val, 111 | a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 112 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 113 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 114 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], 115 | 116 | b00 = a00 * a11 - a01 * a10, 117 | b01 = a00 * a12 - a02 * a10, 118 | b02 = a00 * a13 - a03 * a10, 119 | b03 = a01 * a12 - a02 * a11, 120 | b04 = a01 * a13 - a03 * a11, 121 | b05 = a02 * a13 - a03 * a12, 122 | b06 = a20 * a31 - a21 * a30, 123 | b07 = a20 * a32 - a22 * a30, 124 | b08 = a20 * a33 - a23 * a30, 125 | b09 = a21 * a32 - a22 * a31, 126 | b10 = a21 * a33 - a23 * a31, 127 | b11 = a22 * a33 - a23 * a32, 128 | 129 | // Calculate the determinant 130 | det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; 131 | 132 | if (!det) { 133 | return null; 134 | } 135 | det = 1.0 / det; 136 | 137 | a[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; 138 | a[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; 139 | a[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; 140 | a[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; 141 | a[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; 142 | a[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; 143 | a[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; 144 | a[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; 145 | a[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; 146 | a[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; 147 | a[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; 148 | a[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; 149 | a[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; 150 | a[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; 151 | a[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; 152 | a[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; 153 | return this; 154 | }; 155 | 156 | mat4.adjoint = function() { 157 | var a = this.val, 158 | a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 159 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 160 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 161 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; 162 | 163 | a[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); 164 | a[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); 165 | a[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); 166 | a[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); 167 | a[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); 168 | a[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); 169 | a[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); 170 | a[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); 171 | a[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); 172 | a[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); 173 | a[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); 174 | a[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); 175 | a[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); 176 | a[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); 177 | a[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); 178 | a[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); 179 | return this; 180 | }; 181 | 182 | mat4.determinant = function () { 183 | var a = this.val, 184 | a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 185 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 186 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 187 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], 188 | 189 | b00 = a00 * a11 - a01 * a10, 190 | b01 = a00 * a12 - a02 * a10, 191 | b02 = a00 * a13 - a03 * a10, 192 | b03 = a01 * a12 - a02 * a11, 193 | b04 = a01 * a13 - a03 * a11, 194 | b05 = a02 * a13 - a03 * a12, 195 | b06 = a20 * a31 - a21 * a30, 196 | b07 = a20 * a32 - a22 * a30, 197 | b08 = a20 * a33 - a23 * a30, 198 | b09 = a21 * a32 - a22 * a31, 199 | b10 = a21 * a33 - a23 * a31, 200 | b11 = a22 * a33 - a23 * a32; 201 | 202 | // Calculate the determinant 203 | return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; 204 | }; 205 | 206 | mat4.multiply = function(otherMat) { 207 | var a = this.val, 208 | b = otherMat.val, 209 | a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], 210 | a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], 211 | a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], 212 | a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; 213 | 214 | // Cache only the current line of the second matrix 215 | var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; 216 | a[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 217 | a[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 218 | a[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 219 | a[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 220 | 221 | b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; 222 | a[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 223 | a[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 224 | a[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 225 | a[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 226 | 227 | b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; 228 | a[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 229 | a[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 230 | a[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 231 | a[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 232 | 233 | b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; 234 | a[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; 235 | a[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; 236 | a[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; 237 | a[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; 238 | return this; 239 | }; 240 | 241 | mat4.translate = function(v) { 242 | var x = v.x, y = v.y, z = v.z, 243 | a = this.val; 244 | a[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; 245 | a[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; 246 | a[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; 247 | a[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; 248 | return this; 249 | }; 250 | 251 | mat4.scale = function(v) { 252 | var x = v.x, y = v.y, z = v.z, a = this.val; 253 | 254 | a[0] = a[0] * x; 255 | a[1] = a[1] * x; 256 | a[2] = a[2] * x; 257 | a[3] = a[3] * x; 258 | a[4] = a[4] * y; 259 | a[5] = a[5] * y; 260 | a[6] = a[6] * y; 261 | a[7] = a[7] * y; 262 | a[8] = a[8] * z; 263 | a[9] = a[9] * z; 264 | a[10] = a[10] * z; 265 | a[11] = a[11] * z; 266 | a[12] = a[12]; 267 | a[13] = a[13]; 268 | a[14] = a[14]; 269 | a[15] = a[15]; 270 | return this; 271 | }; 272 | 273 | mat4.rotate = function (rad, axis) { 274 | var a = this.val, 275 | x = axis.x, y = axis.y, z = axis.z, 276 | len = Math.sqrt(x * x + y * y + z * z), 277 | s, c, t, 278 | a00, a01, a02, a03, 279 | a10, a11, a12, a13, 280 | a20, a21, a22, a23, 281 | b00, b01, b02, 282 | b10, b11, b12, 283 | b20, b21, b22; 284 | 285 | if (Math.abs(len) < EPSILON) { return null; } 286 | 287 | len = 1 / len; 288 | x *= len; 289 | y *= len; 290 | z *= len; 291 | 292 | s = Math.sin(rad); 293 | c = Math.cos(rad); 294 | t = 1 - c; 295 | 296 | a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; 297 | a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; 298 | a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; 299 | 300 | // Construct the elements of the rotation matrix 301 | b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; 302 | b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; 303 | b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; 304 | 305 | // Perform rotation-specific matrix multiplication 306 | a[0] = a00 * b00 + a10 * b01 + a20 * b02; 307 | a[1] = a01 * b00 + a11 * b01 + a21 * b02; 308 | a[2] = a02 * b00 + a12 * b01 + a22 * b02; 309 | a[3] = a03 * b00 + a13 * b01 + a23 * b02; 310 | a[4] = a00 * b10 + a10 * b11 + a20 * b12; 311 | a[5] = a01 * b10 + a11 * b11 + a21 * b12; 312 | a[6] = a02 * b10 + a12 * b11 + a22 * b12; 313 | a[7] = a03 * b10 + a13 * b11 + a23 * b12; 314 | a[8] = a00 * b20 + a10 * b21 + a20 * b22; 315 | a[9] = a01 * b20 + a11 * b21 + a21 * b22; 316 | a[10] = a02 * b20 + a12 * b21 + a22 * b22; 317 | a[11] = a03 * b20 + a13 * b21 + a23 * b22; 318 | return this; 319 | }; 320 | 321 | mat4.rotateX = function(rad) { 322 | var a = this.val, 323 | s = Math.sin(rad), 324 | c = Math.cos(rad), 325 | a10 = a[4], 326 | a11 = a[5], 327 | a12 = a[6], 328 | a13 = a[7], 329 | a20 = a[8], 330 | a21 = a[9], 331 | a22 = a[10], 332 | a23 = a[11]; 333 | 334 | // Perform axis-specific matrix multiplication 335 | a[4] = a10 * c + a20 * s; 336 | a[5] = a11 * c + a21 * s; 337 | a[6] = a12 * c + a22 * s; 338 | a[7] = a13 * c + a23 * s; 339 | a[8] = a20 * c - a10 * s; 340 | a[9] = a21 * c - a11 * s; 341 | a[10] = a22 * c - a12 * s; 342 | a[11] = a23 * c - a13 * s; 343 | return this; 344 | }; 345 | 346 | mat4.rotateY = function(rad) { 347 | var a = this.val, 348 | s = Math.sin(rad), 349 | c = Math.cos(rad), 350 | a00 = a[0], 351 | a01 = a[1], 352 | a02 = a[2], 353 | a03 = a[3], 354 | a20 = a[8], 355 | a21 = a[9], 356 | a22 = a[10], 357 | a23 = a[11]; 358 | 359 | // Perform axis-specific matrix multiplication 360 | a[0] = a00 * c - a20 * s; 361 | a[1] = a01 * c - a21 * s; 362 | a[2] = a02 * c - a22 * s; 363 | a[3] = a03 * c - a23 * s; 364 | a[8] = a00 * s + a20 * c; 365 | a[9] = a01 * s + a21 * c; 366 | a[10] = a02 * s + a22 * c; 367 | a[11] = a03 * s + a23 * c; 368 | return this; 369 | }; 370 | 371 | mat4.rotateZ = function (rad) { 372 | var a = this.val, 373 | s = Math.sin(rad), 374 | c = Math.cos(rad), 375 | a00 = a[0], 376 | a01 = a[1], 377 | a02 = a[2], 378 | a03 = a[3], 379 | a10 = a[4], 380 | a11 = a[5], 381 | a12 = a[6], 382 | a13 = a[7]; 383 | 384 | // Perform axis-specific matrix multiplication 385 | a[0] = a00 * c + a10 * s; 386 | a[1] = a01 * c + a11 * s; 387 | a[2] = a02 * c + a12 * s; 388 | a[3] = a03 * c + a13 * s; 389 | a[4] = a10 * c - a00 * s; 390 | a[5] = a11 * c - a01 * s; 391 | a[6] = a12 * c - a02 * s; 392 | a[7] = a13 * c - a03 * s; 393 | return this; 394 | }; 395 | 396 | mat4.fromRotationTranslation = function (q, v) { 397 | // Quaternion math 398 | var out = this.val, 399 | x = q.x, y = q.y, z = q.z, w = q.w, 400 | x2 = x + x, 401 | y2 = y + y, 402 | z2 = z + z, 403 | 404 | xx = x * x2, 405 | xy = x * y2, 406 | xz = x * z2, 407 | yy = y * y2, 408 | yz = y * z2, 409 | zz = z * z2, 410 | wx = w * x2, 411 | wy = w * y2, 412 | wz = w * z2; 413 | 414 | out[0] = 1 - (yy + zz); 415 | out[1] = xy + wz; 416 | out[2] = xz - wy; 417 | out[3] = 0; 418 | out[4] = xy - wz; 419 | out[5] = 1 - (xx + zz); 420 | out[6] = yz + wx; 421 | out[7] = 0; 422 | out[8] = xz + wy; 423 | out[9] = yz - wx; 424 | out[10] = 1 - (xx + yy); 425 | out[11] = 0; 426 | out[12] = v.x; 427 | out[13] = v.y; 428 | out[14] = v.z; 429 | out[15] = 1; 430 | return this; 431 | }; 432 | 433 | mat4.fromQuat = function (q) { 434 | var out = this.val, 435 | x = q.x, y = q.y, z = q.z, w = q.w, 436 | x2 = x + x, 437 | y2 = y + y, 438 | z2 = z + z, 439 | 440 | xx = x * x2, 441 | xy = x * y2, 442 | xz = x * z2, 443 | yy = y * y2, 444 | yz = y * z2, 445 | zz = z * z2, 446 | wx = w * x2, 447 | wy = w * y2, 448 | wz = w * z2; 449 | 450 | out[0] = 1 - (yy + zz); 451 | out[1] = xy + wz; 452 | out[2] = xz - wy; 453 | out[3] = 0; 454 | 455 | out[4] = xy - wz; 456 | out[5] = 1 - (xx + zz); 457 | out[6] = yz + wx; 458 | out[7] = 0; 459 | 460 | out[8] = xz + wy; 461 | out[9] = yz - wx; 462 | out[10] = 1 - (xx + yy); 463 | out[11] = 0; 464 | 465 | out[12] = 0; 466 | out[13] = 0; 467 | out[14] = 0; 468 | out[15] = 1; 469 | 470 | return this; 471 | }; 472 | 473 | 474 | /** 475 | * Generates a frustum matrix with the given bounds 476 | * 477 | * @param {Number} left Left bound of the frustum 478 | * @param {Number} right Right bound of the frustum 479 | * @param {Number} bottom Bottom bound of the frustum 480 | * @param {Number} top Top bound of the frustum 481 | * @param {Number} near Near bound of the frustum 482 | * @param {Number} far Far bound of the frustum 483 | * @returns {Matrix4} this for chaining 484 | */ 485 | mat4.frustum = function (left, right, bottom, top, near, far) { 486 | var out = this.val, 487 | rl = 1 / (right - left), 488 | tb = 1 / (top - bottom), 489 | nf = 1 / (near - far); 490 | out[0] = (near * 2) * rl; 491 | out[1] = 0; 492 | out[2] = 0; 493 | out[3] = 0; 494 | out[4] = 0; 495 | out[5] = (near * 2) * tb; 496 | out[6] = 0; 497 | out[7] = 0; 498 | out[8] = (right + left) * rl; 499 | out[9] = (top + bottom) * tb; 500 | out[10] = (far + near) * nf; 501 | out[11] = -1; 502 | out[12] = 0; 503 | out[13] = 0; 504 | out[14] = (far * near * 2) * nf; 505 | out[15] = 0; 506 | return this; 507 | }; 508 | 509 | 510 | /** 511 | * Generates a perspective projection matrix with the given bounds 512 | * 513 | * @param {number} fovy Vertical field of view in radians 514 | * @param {number} aspect Aspect ratio. typically viewport width/height 515 | * @param {number} near Near bound of the frustum 516 | * @param {number} far Far bound of the frustum 517 | * @returns {Matrix4} this for chaining 518 | */ 519 | mat4.perspective = function (fovy, aspect, near, far) { 520 | var out = this.val, 521 | f = 1.0 / Math.tan(fovy / 2), 522 | nf = 1 / (near - far); 523 | out[0] = f / aspect; 524 | out[1] = 0; 525 | out[2] = 0; 526 | out[3] = 0; 527 | out[4] = 0; 528 | out[5] = f; 529 | out[6] = 0; 530 | out[7] = 0; 531 | out[8] = 0; 532 | out[9] = 0; 533 | out[10] = (far + near) * nf; 534 | out[11] = -1; 535 | out[12] = 0; 536 | out[13] = 0; 537 | out[14] = (2 * far * near) * nf; 538 | out[15] = 0; 539 | return this; 540 | }; 541 | 542 | /** 543 | * Generates a orthogonal projection matrix with the given bounds 544 | * 545 | * @param {number} left Left bound of the frustum 546 | * @param {number} right Right bound of the frustum 547 | * @param {number} bottom Bottom bound of the frustum 548 | * @param {number} top Top bound of the frustum 549 | * @param {number} near Near bound of the frustum 550 | * @param {number} far Far bound of the frustum 551 | * @returns {Matrix4} this for chaining 552 | */ 553 | mat4.ortho = function (left, right, bottom, top, near, far) { 554 | var out = this.val, 555 | lr = left-right, 556 | bt = bottom-top, 557 | nf = near-far; 558 | 559 | //avoid division by zero 560 | lr = lr===0 ? lr : 1/lr; 561 | bt = bt===0 ? bt : 1/bt; 562 | nf = nf===0 ? nf : 1/nf; 563 | 564 | out[0] = -2 * lr; 565 | out[1] = 0; 566 | out[2] = 0; 567 | out[3] = 0; 568 | out[4] = 0; 569 | out[5] = -2 * bt; 570 | out[6] = 0; 571 | out[7] = 0; 572 | out[8] = 0; 573 | out[9] = 0; 574 | out[10] = 2 * nf; 575 | out[11] = 0; 576 | out[12] = (left + right) * lr; 577 | out[13] = (top + bottom) * bt; 578 | out[14] = (far + near) * nf; 579 | out[15] = 1; 580 | return this; 581 | }; 582 | 583 | /** 584 | * Generates a look-at matrix with the given eye position, focal point, and up axis 585 | * 586 | * @param {Vector3} eye Position of the viewer 587 | * @param {Vector3} center Point the viewer is looking at 588 | * @param {Vector3} up vec3 pointing up 589 | * @returns {Matrix4} this for chaining 590 | */ 591 | mat4.lookAt = function (eye, center, up) { 592 | var out = this.val, 593 | 594 | x0, x1, x2, y0, y1, y2, z0, z1, z2, len, 595 | eyex = eye.x, 596 | eyey = eye.y, 597 | eyez = eye.z, 598 | upx = up.x, 599 | upy = up.y, 600 | upz = up.z, 601 | centerx = center.x, 602 | centery = center.y, 603 | centerz = center.z; 604 | 605 | if (Math.abs(eyex - centerx) < EPSILON && 606 | Math.abs(eyey - centery) < EPSILON && 607 | Math.abs(eyez - centerz) < EPSILON) { 608 | return this.identity(); 609 | } 610 | 611 | z0 = eyex - centerx; 612 | z1 = eyey - centery; 613 | z2 = eyez - centerz; 614 | 615 | len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); 616 | z0 *= len; 617 | z1 *= len; 618 | z2 *= len; 619 | 620 | x0 = upy * z2 - upz * z1; 621 | x1 = upz * z0 - upx * z2; 622 | x2 = upx * z1 - upy * z0; 623 | len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); 624 | if (!len) { 625 | x0 = 0; 626 | x1 = 0; 627 | x2 = 0; 628 | } else { 629 | len = 1 / len; 630 | x0 *= len; 631 | x1 *= len; 632 | x2 *= len; 633 | } 634 | 635 | y0 = z1 * x2 - z2 * x1; 636 | y1 = z2 * x0 - z0 * x2; 637 | y2 = z0 * x1 - z1 * x0; 638 | 639 | len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); 640 | if (!len) { 641 | y0 = 0; 642 | y1 = 0; 643 | y2 = 0; 644 | } else { 645 | len = 1 / len; 646 | y0 *= len; 647 | y1 *= len; 648 | y2 *= len; 649 | } 650 | 651 | out[0] = x0; 652 | out[1] = y0; 653 | out[2] = z0; 654 | out[3] = 0; 655 | out[4] = x1; 656 | out[5] = y1; 657 | out[6] = z1; 658 | out[7] = 0; 659 | out[8] = x2; 660 | out[9] = y2; 661 | out[10] = z2; 662 | out[11] = 0; 663 | out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); 664 | out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); 665 | out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); 666 | out[15] = 1; 667 | 668 | return this; 669 | }; 670 | 671 | 672 | mat4.mul = mat4.multiply; 673 | 674 | mat4.idt = mat4.identity; 675 | 676 | //This is handy for Pool utilities, to "reset" a 677 | //shared object to its default state 678 | mat4.reset = mat4.idt; 679 | 680 | mat4.toString = function () { 681 | var a = this.val; 682 | return 'Matrix4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + 683 | a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + 684 | a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + 685 | a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; 686 | }; 687 | 688 | mat4.str = mat4.toString; 689 | 690 | module.exports = Matrix4; 691 | -------------------------------------------------------------------------------- /lib/Quaternion.js: -------------------------------------------------------------------------------- 1 | var Vector3 = require('./Vector3'); 2 | var Matrix3 = require('./Matrix3'); 3 | var common = require('./common'); 4 | 5 | //some shared 'private' arrays 6 | var s_iNext = (typeof Int8Array !== 'undefined' ? new Int8Array([1,2,0]) : [1,2,0]); 7 | var tmp = (typeof Float32Array !== 'undefined' ? new Float32Array([0,0,0]) : [0,0,0]); 8 | 9 | var xUnitVec3 = new Vector3(1, 0, 0); 10 | var yUnitVec3 = new Vector3(0, 1, 0); 11 | var tmpvec = new Vector3(); 12 | 13 | var tmpMat3 = new Matrix3(); 14 | 15 | function Quaternion(x, y, z, w) { 16 | if (typeof x === "object") { 17 | this.x = x.x||0; 18 | this.y = x.y||0; 19 | this.z = x.z||0; 20 | this.w = x.w||0; 21 | } else { 22 | this.x = x||0; 23 | this.y = y||0; 24 | this.z = z||0; 25 | this.w = w||0; 26 | } 27 | } 28 | 29 | var quat = Quaternion.prototype; 30 | 31 | //mixin common functions 32 | for (var k in common) { 33 | quat[k] = common[k]; 34 | } 35 | 36 | quat.rotationTo = function(a, b) { 37 | var dot = a.x * b.x + a.y * b.y + a.z * b.z; //a.dot(b) 38 | if (dot < -0.999999) { 39 | if (tmpvec.copy(xUnitVec3).cross(a).len() < 0.000001) 40 | tmpvec.copy(yUnitVec3).cross(a); 41 | 42 | tmpvec.normalize(); 43 | return this.setAxisAngle(tmpvec, Math.PI); 44 | } else if (dot > 0.999999) { 45 | this.x = 0; 46 | this.y = 0; 47 | this.z = 0; 48 | this.w = 1; 49 | return this; 50 | } else { 51 | tmpvec.copy(a).cross(b); 52 | this.x = tmpvec.x; 53 | this.y = tmpvec.y; 54 | this.z = tmpvec.z; 55 | this.w = 1 + dot; 56 | return this.normalize(); 57 | } 58 | }; 59 | 60 | quat.setAxes = function(view, right, up) { 61 | var m = tmpMat3.val; 62 | m[0] = right.x; 63 | m[3] = right.y; 64 | m[6] = right.z; 65 | 66 | m[1] = up.x; 67 | m[4] = up.y; 68 | m[7] = up.z; 69 | 70 | m[2] = -view.x; 71 | m[5] = -view.y; 72 | m[8] = -view.z; 73 | 74 | return this.fromMat3(tmpMat3).normalize(); 75 | }; 76 | 77 | quat.identity = function() { 78 | this.x = this.y = this.z = 0; 79 | this.w = 1; 80 | return this; 81 | }; 82 | 83 | quat.setAxisAngle = function(axis, rad) { 84 | rad = rad * 0.5; 85 | var s = Math.sin(rad); 86 | this.x = s * axis.x; 87 | this.y = s * axis.y; 88 | this.z = s * axis.z; 89 | this.w = Math.cos(rad); 90 | return this; 91 | }; 92 | 93 | quat.multiply = function(b) { 94 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 95 | bx = b.x, by = b.y, bz = b.z, bw = b.w; 96 | 97 | this.x = ax * bw + aw * bx + ay * bz - az * by; 98 | this.y = ay * bw + aw * by + az * bx - ax * bz; 99 | this.z = az * bw + aw * bz + ax * by - ay * bx; 100 | this.w = aw * bw - ax * bx - ay * by - az * bz; 101 | return this; 102 | }; 103 | 104 | quat.slerp = function (b, t) { 105 | // benchmarks: 106 | // http://jsperf.com/quaternion-slerp-implementations 107 | 108 | var ax = this.x, ay = this.y, az = this.y, aw = this.y, 109 | bx = b.x, by = b.y, bz = b.z, bw = b.w; 110 | 111 | var omega, cosom, sinom, scale0, scale1; 112 | 113 | // calc cosine 114 | cosom = ax * bx + ay * by + az * bz + aw * bw; 115 | // adjust signs (if necessary) 116 | if ( cosom < 0.0 ) { 117 | cosom = -cosom; 118 | bx = - bx; 119 | by = - by; 120 | bz = - bz; 121 | bw = - bw; 122 | } 123 | // calculate coefficients 124 | if ( (1.0 - cosom) > 0.000001 ) { 125 | // standard case (slerp) 126 | omega = Math.acos(cosom); 127 | sinom = Math.sin(omega); 128 | scale0 = Math.sin((1.0 - t) * omega) / sinom; 129 | scale1 = Math.sin(t * omega) / sinom; 130 | } else { 131 | // "from" and "to" quaternions are very close 132 | // ... so we can do a linear interpolation 133 | scale0 = 1.0 - t; 134 | scale1 = t; 135 | } 136 | // calculate final values 137 | this.x = scale0 * ax + scale1 * bx; 138 | this.y = scale0 * ay + scale1 * by; 139 | this.z = scale0 * az + scale1 * bz; 140 | this.w = scale0 * aw + scale1 * bw; 141 | return this; 142 | }; 143 | 144 | quat.invert = function() { 145 | var a0 = this.x, a1 = this.y, a2 = this.z, a3 = this.w, 146 | dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, 147 | invDot = dot ? 1.0/dot : 0; 148 | 149 | // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 150 | 151 | this.x = -a0*invDot; 152 | this.y = -a1*invDot; 153 | this.z = -a2*invDot; 154 | this.w = a3*invDot; 155 | return this; 156 | }; 157 | 158 | quat.conjugate = function() { 159 | this.x = -this.x; 160 | this.y = -this.y; 161 | this.z = -this.z; 162 | return this; 163 | }; 164 | 165 | quat.rotateX = function (rad) { 166 | rad *= 0.5; 167 | 168 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 169 | bx = Math.sin(rad), bw = Math.cos(rad); 170 | 171 | this.x = ax * bw + aw * bx; 172 | this.y = ay * bw + az * bx; 173 | this.z = az * bw - ay * bx; 174 | this.w = aw * bw - ax * bx; 175 | return this; 176 | }; 177 | 178 | quat.rotateY = function (rad) { 179 | rad *= 0.5; 180 | 181 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 182 | by = Math.sin(rad), bw = Math.cos(rad); 183 | 184 | this.x = ax * bw - az * by; 185 | this.y = ay * bw + aw * by; 186 | this.z = az * bw + ax * by; 187 | this.w = aw * bw - ay * by; 188 | return this; 189 | }; 190 | 191 | quat.rotateZ = function (rad) { 192 | rad *= 0.5; 193 | 194 | var ax = this.x, ay = this.y, az = this.z, aw = this.w, 195 | bz = Math.sin(rad), bw = Math.cos(rad); 196 | 197 | this.x = ax * bw + ay * bz; 198 | this.y = ay * bw - ax * bz; 199 | this.z = az * bw + aw * bz; 200 | this.w = aw * bw - az * bz; 201 | return this; 202 | }; 203 | 204 | quat.calculateW = function () { 205 | var x = this.x, y = this.y, z = this.z; 206 | 207 | this.x = x; 208 | this.y = y; 209 | this.z = z; 210 | this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); 211 | return this; 212 | }; 213 | 214 | quat.fromMat3 = function(mat) { 215 | // benchmarks: 216 | // http://jsperf.com/typed-array-access-speed 217 | // http://jsperf.com/conversion-of-3x3-matrix-to-quaternion 218 | 219 | // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes 220 | // article "Quaternion Calculus and Fast Animation". 221 | var m = mat.val, 222 | fTrace = m[0] + m[4] + m[8]; 223 | var fRoot; 224 | 225 | if ( fTrace > 0.0 ) { 226 | // |w| > 1/2, may as well choose w > 1/2 227 | fRoot = Math.sqrt(fTrace + 1.0); // 2w 228 | this.w = 0.5 * fRoot; 229 | fRoot = 0.5/fRoot; // 1/(4w) 230 | this.x = (m[7]-m[5])*fRoot; 231 | this.y = (m[2]-m[6])*fRoot; 232 | this.z = (m[3]-m[1])*fRoot; 233 | } else { 234 | // |w| <= 1/2 235 | var i = 0; 236 | if ( m[4] > m[0] ) 237 | i = 1; 238 | if ( m[8] > m[i*3+i] ) 239 | i = 2; 240 | var j = s_iNext[i]; 241 | var k = s_iNext[j]; 242 | 243 | //This isn't quite as clean without array access... 244 | fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); 245 | tmp[i] = 0.5 * fRoot; 246 | 247 | fRoot = 0.5 / fRoot; 248 | tmp[j] = (m[j*3+i] + m[i*3+j]) * fRoot; 249 | tmp[k] = (m[k*3+i] + m[i*3+k]) * fRoot; 250 | 251 | this.x = tmp[0]; 252 | this.y = tmp[1]; 253 | this.z = tmp[2]; 254 | this.w = (m[k*3+j] - m[j*3+k]) * fRoot; 255 | } 256 | 257 | return this; 258 | }; 259 | 260 | quat.idt = quat.identity; 261 | 262 | quat.sub = quat.subtract; 263 | 264 | quat.mul = quat.multiply; 265 | 266 | quat.len = quat.length; 267 | 268 | quat.lenSq = quat.lengthSq; 269 | 270 | //This is handy for Pool utilities, to "reset" a 271 | //shared object to its default state 272 | quat.reset = quat.idt; 273 | 274 | 275 | quat.toString = function() { 276 | return 'Quaternion(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')'; 277 | }; 278 | 279 | quat.str = quat.toString; 280 | 281 | module.exports = Quaternion; -------------------------------------------------------------------------------- /lib/Vector2.js: -------------------------------------------------------------------------------- 1 | function Vector2(x, y) { 2 | if (typeof x === "object") { 3 | this.x = x.x||0; 4 | this.y = x.y||0; 5 | } else { 6 | this.x = x||0; 7 | this.y = y||0; 8 | } 9 | } 10 | 11 | //shorthand it for better minification 12 | var vec2 = Vector2.prototype; 13 | 14 | /** 15 | * Returns a new instance of Vector2 with 16 | * this vector's components. 17 | * @return {Vector2} a clone of this vector 18 | */ 19 | vec2.clone = function() { 20 | return new Vector2(this.x, this.y); 21 | }; 22 | 23 | /** 24 | * Copies the x, y components from the specified 25 | * Vector. Any undefined components from `otherVec` 26 | * will default to zero. 27 | * 28 | * @param {otherVec} the other Vector2 to copy 29 | * @return {Vector2} this, for chaining 30 | */ 31 | vec2.copy = function(otherVec) { 32 | this.x = otherVec.x||0; 33 | this.y = otherVec.y||0; 34 | return this; 35 | }; 36 | 37 | /** 38 | * A convenience function to set the components of 39 | * this vector as x and y. Falsy or undefined 40 | * parameters will default to zero. 41 | * 42 | * You can also pass a vector object instead of 43 | * individual components, to copy the object's components. 44 | * 45 | * @param {Number} x the x component 46 | * @param {Number} y the y component 47 | * @return {Vector2} this, for chaining 48 | */ 49 | vec2.set = function(x, y) { 50 | if (typeof x === "object") { 51 | this.x = x.x||0; 52 | this.y = x.y||0; 53 | } else { 54 | this.x = x||0; 55 | this.y = y||0; 56 | } 57 | return this; 58 | }; 59 | 60 | vec2.add = function(v) { 61 | this.x += v.x; 62 | this.y += v.y; 63 | return this; 64 | }; 65 | 66 | vec2.subtract = function(v) { 67 | this.x -= v.x; 68 | this.y -= v.y; 69 | return this; 70 | }; 71 | 72 | vec2.multiply = function(v) { 73 | this.x *= v.x; 74 | this.y *= v.y; 75 | return this; 76 | }; 77 | 78 | vec2.scale = function(s) { 79 | this.x *= s; 80 | this.y *= s; 81 | return this; 82 | }; 83 | 84 | vec2.divide = function(v) { 85 | this.x /= v.x; 86 | this.y /= v.y; 87 | return this; 88 | }; 89 | 90 | vec2.negate = function() { 91 | this.x = -this.x; 92 | this.y = -this.y; 93 | return this; 94 | }; 95 | 96 | vec2.distance = function(v) { 97 | var dx = v.x - this.x, 98 | dy = v.y - this.y; 99 | return Math.sqrt(dx*dx + dy*dy); 100 | }; 101 | 102 | vec2.distanceSq = function(v) { 103 | var dx = v.x - this.x, 104 | dy = v.y - this.y; 105 | return dx*dx + dy*dy; 106 | }; 107 | 108 | vec2.length = function() { 109 | var x = this.x, 110 | y = this.y; 111 | return Math.sqrt(x*x + y*y); 112 | }; 113 | 114 | vec2.lengthSq = function() { 115 | var x = this.x, 116 | y = this.y; 117 | return x*x + y*y; 118 | }; 119 | 120 | vec2.normalize = function() { 121 | var x = this.x, 122 | y = this.y; 123 | var len = x*x + y*y; 124 | if (len > 0) { 125 | len = 1 / Math.sqrt(len); 126 | this.x = x*len; 127 | this.y = y*len; 128 | } 129 | return this; 130 | }; 131 | 132 | vec2.dot = function(v) { 133 | return this.x * v.x + this.y * v.y; 134 | }; 135 | 136 | //Unlike Vector3, this returns a scalar 137 | //http://allenchou.net/2013/07/cross-product-of-2d-vectors/ 138 | vec2.cross = function(v) { 139 | return this.x * v.y - this.y * v.x; 140 | }; 141 | 142 | vec2.lerp = function(v, t) { 143 | var ax = this.x, 144 | ay = this.y; 145 | t = t||0; 146 | this.x = ax + t * (v.x - ax); 147 | this.y = ay + t * (v.y - ay); 148 | return this; 149 | }; 150 | 151 | vec2.transformMat3 = function(mat) { 152 | var x = this.x, y = this.y, m = mat.val; 153 | this.x = m[0] * x + m[3] * y + m[6]; 154 | this.y = m[1] * x + m[4] * y + m[7]; 155 | return this; 156 | }; 157 | 158 | vec2.transformMat4 = function(mat) { 159 | var x = this.x, 160 | y = this.y, 161 | m = mat.val; 162 | this.x = m[0] * x + m[4] * y + m[12]; 163 | this.y = m[1] * x + m[5] * y + m[13]; 164 | return this; 165 | }; 166 | 167 | vec2.reset = function() { 168 | this.x = 0; 169 | this.y = 0; 170 | return this; 171 | }; 172 | 173 | vec2.sub = vec2.subtract; 174 | 175 | vec2.mul = vec2.multiply; 176 | 177 | vec2.div = vec2.divide; 178 | 179 | vec2.dist = vec2.distance; 180 | 181 | vec2.distSq = vec2.distanceSq; 182 | 183 | vec2.len = vec2.length; 184 | 185 | vec2.lenSq = vec2.lengthSq; 186 | 187 | vec2.toString = function() { 188 | return 'Vector2(' + this.x + ', ' + this.y + ')'; 189 | }; 190 | 191 | vec2.random = function(scale) { 192 | scale = scale || 1.0; 193 | var r = Math.random() * 2.0 * Math.PI; 194 | this.x = Math.cos(r) * scale; 195 | this.y = Math.sin(r) * scale; 196 | return this; 197 | }; 198 | 199 | vec2.str = vec2.toString; 200 | 201 | module.exports = Vector2; -------------------------------------------------------------------------------- /lib/Vector3.js: -------------------------------------------------------------------------------- 1 | function Vector3(x, y, z) { 2 | if (typeof x === "object") { 3 | this.x = x.x||0; 4 | this.y = x.y||0; 5 | this.z = x.z||0; 6 | } else { 7 | this.x = x||0; 8 | this.y = y||0; 9 | this.z = z||0; 10 | } 11 | } 12 | 13 | //shorthand it for better minification 14 | var vec3 = Vector3.prototype; 15 | 16 | vec3.clone = function() { 17 | return new Vector3(this.x, this.y, this.z); 18 | }; 19 | 20 | vec3.copy = function(otherVec) { 21 | this.x = otherVec.x; 22 | this.y = otherVec.y; 23 | this.z = otherVec.z; 24 | return this; 25 | }; 26 | 27 | vec3.set = function(x, y, z) { 28 | if (typeof x === "object") { 29 | this.x = x.x||0; 30 | this.y = x.y||0; 31 | this.z = x.z||0; 32 | } else { 33 | this.x = x||0; 34 | this.y = y||0; 35 | this.z = z||0; 36 | } 37 | return this; 38 | }; 39 | 40 | vec3.add = function(v) { 41 | this.x += v.x; 42 | this.y += v.y; 43 | this.z += v.z; 44 | return this; 45 | }; 46 | 47 | vec3.subtract = function(v) { 48 | this.x -= v.x; 49 | this.y -= v.y; 50 | this.z -= v.z; 51 | return this; 52 | }; 53 | 54 | vec3.multiply = function(v) { 55 | this.x *= v.x; 56 | this.y *= v.y; 57 | this.z *= v.z; 58 | return this; 59 | }; 60 | 61 | vec3.scale = function(s) { 62 | this.x *= s; 63 | this.y *= s; 64 | this.z *= s; 65 | return this; 66 | }; 67 | 68 | vec3.divide = function(v) { 69 | this.x /= v.x; 70 | this.y /= v.y; 71 | this.z /= v.z; 72 | return this; 73 | }; 74 | 75 | vec3.negate = function() { 76 | this.x = -this.x; 77 | this.y = -this.y; 78 | this.z = -this.z; 79 | return this; 80 | }; 81 | 82 | vec3.distance = function(v) { 83 | var dx = v.x - this.x, 84 | dy = v.y - this.y, 85 | dz = v.z - this.z; 86 | return Math.sqrt(dx*dx + dy*dy + dz*dz); 87 | }; 88 | 89 | vec3.distanceSq = function(v) { 90 | var dx = v.x - this.x, 91 | dy = v.y - this.y, 92 | dz = v.z - this.z; 93 | return dx*dx + dy*dy + dz*dz; 94 | }; 95 | 96 | vec3.length = function() { 97 | var x = this.x, 98 | y = this.y, 99 | z = this.z; 100 | return Math.sqrt(x*x + y*y + z*z); 101 | }; 102 | 103 | vec3.lengthSq = function() { 104 | var x = this.x, 105 | y = this.y, 106 | z = this.z; 107 | return x*x + y*y + z*z; 108 | }; 109 | 110 | vec3.normalize = function() { 111 | var x = this.x, 112 | y = this.y, 113 | z = this.z; 114 | var len = x*x + y*y + z*z; 115 | if (len > 0) { 116 | len = 1 / Math.sqrt(len); 117 | this.x = x*len; 118 | this.y = y*len; 119 | this.z = z*len; 120 | } 121 | return this; 122 | }; 123 | 124 | vec3.dot = function(v) { 125 | return this.x * v.x + this.y * v.y + this.z * v.z; 126 | }; 127 | 128 | vec3.cross = function(v) { 129 | var ax = this.x, ay = this.y, az = this.z, 130 | bx = v.x, by = v.y, bz = v.z; 131 | 132 | this.x = ay * bz - az * by; 133 | this.y = az * bx - ax * bz; 134 | this.z = ax * by - ay * bx; 135 | return this; 136 | }; 137 | 138 | vec3.lerp = function(v, t) { 139 | var ax = this.x, 140 | ay = this.y, 141 | az = this.z; 142 | t = t||0; 143 | this.x = ax + t * (v.x - ax); 144 | this.y = ay + t * (v.y - ay); 145 | this.z = az + t * (v.z - az); 146 | return this; 147 | }; 148 | 149 | vec3.transformMat4 = function(mat) { 150 | var x = this.x, y = this.y, z = this.z, m = mat.val; 151 | this.x = m[0] * x + m[4] * y + m[8] * z + m[12]; 152 | this.y = m[1] * x + m[5] * y + m[9] * z + m[13]; 153 | this.z = m[2] * x + m[6] * y + m[10] * z + m[14]; 154 | return this; 155 | }; 156 | 157 | vec3.transformMat3 = function(mat) { 158 | var x = this.x, y = this.y, z = this.z, m = mat.val; 159 | this.x = x * m[0] + y * m[3] + z * m[6]; 160 | this.y = x * m[1] + y * m[4] + z * m[7]; 161 | this.z = x * m[2] + y * m[5] + z * m[8]; 162 | return this; 163 | }; 164 | 165 | vec3.transformQuat = function(q) { 166 | // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations 167 | var x = this.x, y = this.y, z = this.z, 168 | qx = q.x, qy = q.y, qz = q.z, qw = q.w, 169 | 170 | // calculate quat * vec 171 | ix = qw * x + qy * z - qz * y, 172 | iy = qw * y + qz * x - qx * z, 173 | iz = qw * z + qx * y - qy * x, 174 | iw = -qx * x - qy * y - qz * z; 175 | 176 | // calculate result * inverse quat 177 | this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; 178 | this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; 179 | this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; 180 | return this; 181 | }; 182 | 183 | /** 184 | * Multiplies this Vector3 by the specified matrix, 185 | * applying a W divide. This is useful for projection, 186 | * e.g. unprojecting a 2D point into 3D space. 187 | * 188 | * @method prj 189 | * @param {Matrix4} the 4x4 matrix to multiply with 190 | * @return {Vector3} this object for chaining 191 | */ 192 | vec3.project = function(mat) { 193 | var x = this.x, 194 | y = this.y, 195 | z = this.z, 196 | m = mat.val, 197 | a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3], 198 | a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7], 199 | a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11], 200 | a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15]; 201 | 202 | var l_w = 1 / (x * a03 + y * a13 + z * a23 + a33); 203 | 204 | this.x = (x * a00 + y * a10 + z * a20 + a30) * l_w; 205 | this.y = (x * a01 + y * a11 + z * a21 + a31) * l_w; 206 | this.z = (x * a02 + y * a12 + z * a22 + a32) * l_w; 207 | return this; 208 | }; 209 | 210 | /** 211 | * Unproject this point from 2D space to 3D space. 212 | * The point should have its x and y properties set to 213 | * 2D screen space, and the z either at 0 (near plane) 214 | * or 1 (far plane). The provided matrix is assumed to already 215 | * be combined, i.e. projection * view * model. 216 | * 217 | * After this operation, this vector's (x, y, z) components will 218 | * represent the unprojected 3D coordinate. 219 | * 220 | * @param {Vector4} viewport screen x, y, width and height in pixels 221 | * @param {Matrix4} invProjectionView combined projection and view matrix 222 | * @return {Vector3} this object, for chaining 223 | */ 224 | vec3.unproject = function(viewport, invProjectionView) { 225 | var viewX = viewport.x, 226 | viewY = viewport.y, 227 | viewWidth = viewport.z, 228 | viewHeight = viewport.w; 229 | 230 | var x = this.x, 231 | y = this.y, 232 | z = this.z; 233 | 234 | x = x - viewX; 235 | y = viewHeight - y - 1; 236 | y = y - viewY; 237 | 238 | this.x = (2 * x) / viewWidth - 1; 239 | this.y = (2 * y) / viewHeight - 1; 240 | this.z = 2 * z - 1; 241 | 242 | return this.project(invProjectionView); 243 | }; 244 | 245 | vec3.random = function(scale) { 246 | scale = scale || 1.0; 247 | 248 | var r = Math.random() * 2.0 * Math.PI; 249 | var z = (Math.random() * 2.0) - 1.0; 250 | var zScale = Math.sqrt(1.0-z*z) * scale; 251 | 252 | this.x = Math.cos(r) * zScale; 253 | this.y = Math.sin(r) * zScale; 254 | this.z = z * scale; 255 | return this; 256 | }; 257 | 258 | vec3.reset = function() { 259 | this.x = 0; 260 | this.y = 0; 261 | this.z = 0; 262 | return this; 263 | }; 264 | 265 | 266 | vec3.sub = vec3.subtract; 267 | 268 | vec3.mul = vec3.multiply; 269 | 270 | vec3.div = vec3.divide; 271 | 272 | vec3.dist = vec3.distance; 273 | 274 | vec3.distSq = vec3.distanceSq; 275 | 276 | vec3.len = vec3.length; 277 | 278 | vec3.lenSq = vec3.lengthSq; 279 | 280 | vec3.toString = function() { 281 | return 'Vector3(' + this.x + ', ' + this.y + ', ' + this.z + ')'; 282 | }; 283 | 284 | vec3.str = vec3.toString; 285 | 286 | module.exports = Vector3; -------------------------------------------------------------------------------- /lib/Vector4.js: -------------------------------------------------------------------------------- 1 | var common = require('./common'); 2 | 3 | function Vector4(x, y, z, w) { 4 | if (typeof x === "object") { 5 | this.x = x.x||0; 6 | this.y = x.y||0; 7 | this.z = x.z||0; 8 | this.w = x.w||0; 9 | } else { 10 | this.x = x||0; 11 | this.y = y||0; 12 | this.z = z||0; 13 | this.w = w||0; 14 | } 15 | } 16 | 17 | //shorthand it for better minification 18 | var vec4 = Vector4.prototype; 19 | 20 | //mixin common functions 21 | for (var k in common) { 22 | vec4[k] = common[k]; 23 | } 24 | 25 | vec4.clone = function() { 26 | return new Vector4(this.x, this.y, this.z, this.w); 27 | }; 28 | 29 | vec4.multiply = function(v) { 30 | this.x *= v.x; 31 | this.y *= v.y; 32 | this.z *= v.z; 33 | this.w *= v.w; 34 | return this; 35 | }; 36 | 37 | vec4.divide = function(v) { 38 | this.x /= v.x; 39 | this.y /= v.y; 40 | this.z /= v.z; 41 | this.w /= v.w; 42 | return this; 43 | }; 44 | 45 | vec4.distance = function(v) { 46 | var dx = v.x - this.x, 47 | dy = v.y - this.y, 48 | dz = v.z - this.z, 49 | dw = v.w - this.w; 50 | return Math.sqrt(dx*dx + dy*dy + dz*dz + dw*dw); 51 | }; 52 | 53 | vec4.distanceSq = function(v) { 54 | var dx = v.x - this.x, 55 | dy = v.y - this.y, 56 | dz = v.z - this.z, 57 | dw = v.w - this.w; 58 | return dx*dx + dy*dy + dz*dz + dw*dw; 59 | }; 60 | 61 | vec4.negate = function() { 62 | this.x = -this.x; 63 | this.y = -this.y; 64 | this.z = -this.z; 65 | this.w = -this.w; 66 | return this; 67 | }; 68 | 69 | vec4.transformMat4 = function(mat) { 70 | var m = mat.val, x = this.x, y = this.y, z = this.z, w = this.w; 71 | this.x = m[0] * x + m[4] * y + m[8] * z + m[12] * w; 72 | this.y = m[1] * x + m[5] * y + m[9] * z + m[13] * w; 73 | this.z = m[2] * x + m[6] * y + m[10] * z + m[14] * w; 74 | this.w = m[3] * x + m[7] * y + m[11] * z + m[15] * w; 75 | return this; 76 | }; 77 | 78 | //// TODO: is this really the same as Vector3 ?? 79 | /// Also, what about this: 80 | /// http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/ 81 | vec4.transformQuat = function(q) { 82 | // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations 83 | var x = this.x, y = this.y, z = this.z, 84 | qx = q.x, qy = q.y, qz = q.z, qw = q.w, 85 | 86 | // calculate quat * vec 87 | ix = qw * x + qy * z - qz * y, 88 | iy = qw * y + qz * x - qx * z, 89 | iz = qw * z + qx * y - qy * x, 90 | iw = -qx * x - qy * y - qz * z; 91 | 92 | // calculate result * inverse quat 93 | this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; 94 | this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; 95 | this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; 96 | return this; 97 | }; 98 | 99 | vec4.random = function(scale) { 100 | scale = scale || 1.0; 101 | 102 | //Not spherical; should fix this for more uniform distribution 103 | this.x = (Math.random() * 2 - 1) * scale; 104 | this.y = (Math.random() * 2 - 1) * scale; 105 | this.z = (Math.random() * 2 - 1) * scale; 106 | this.w = (Math.random() * 2 - 1) * scale; 107 | return this; 108 | }; 109 | 110 | vec4.reset = function() { 111 | this.x = 0; 112 | this.y = 0; 113 | this.z = 0; 114 | this.w = 0; 115 | return this; 116 | }; 117 | 118 | vec4.sub = vec4.subtract; 119 | 120 | vec4.mul = vec4.multiply; 121 | 122 | vec4.div = vec4.divide; 123 | 124 | vec4.dist = vec4.distance; 125 | 126 | vec4.distSq = vec4.distanceSq; 127 | 128 | vec4.len = vec4.length; 129 | 130 | vec4.lenSq = vec4.lengthSq; 131 | 132 | vec4.toString = function() { 133 | return 'Vector4(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')'; 134 | }; 135 | 136 | vec4.str = vec4.toString; 137 | 138 | module.exports = Vector4; -------------------------------------------------------------------------------- /lib/common.js: -------------------------------------------------------------------------------- 1 | //common vec4 functions 2 | module.exports = { 3 | 4 | /** 5 | * Copies the x, y, z, w components from the specified 6 | * Vector. Unlike most other operations, this function 7 | * will default undefined components on `otherVec` to zero. 8 | * 9 | * @method copy 10 | * @param {otherVec} the other Vector4 to copy 11 | * @return {Vector} this, for chaining 12 | */ 13 | 14 | 15 | /** 16 | * A convenience function to set the components of 17 | * this vector as x, y, z, w. Falsy or undefined 18 | * parameters will default to zero. 19 | * 20 | * You can also pass a vector object instead of 21 | * individual components, to copy the object's components. 22 | * 23 | * @method set 24 | * @param {Number} x the x component 25 | * @param {Number} y the y component 26 | * @param {Number} z the z component 27 | * @param {Number} w the w component 28 | * @return {Vector2} this, for chaining 29 | */ 30 | 31 | /** 32 | * Adds the components of the other Vector4 to 33 | * this vector. 34 | * 35 | * @method add 36 | * @param {Vector4} otherVec other vector, right operand 37 | * @return {Vector2} this, for chaining 38 | */ 39 | 40 | /** 41 | * Subtracts the components of the other Vector4 42 | * from this vector. Aliased as `sub()` 43 | * 44 | * @method subtract 45 | * @param {Vector4} otherVec other vector, right operand 46 | * @return {Vector2} this, for chaining 47 | */ 48 | 49 | /** 50 | * Multiplies the components of this Vector4 51 | * by a scalar amount. 52 | * 53 | * @method scale 54 | * @param {Number} s the scale to multiply by 55 | * @return {Vector4} this, for chaining 56 | */ 57 | 58 | /** 59 | * Returns the magnitude (length) of this vector. 60 | * 61 | * Aliased as `len()` 62 | * 63 | * @method length 64 | * @return {Number} the length of this vector 65 | */ 66 | 67 | /** 68 | * Returns the squared magnitude (length) of this vector. 69 | * 70 | * Aliased as `lenSq()` 71 | * 72 | * @method lengthSq 73 | * @return {Number} the squared length of this vector 74 | */ 75 | 76 | /** 77 | * Normalizes this vector to a unit vector. 78 | * @method normalize 79 | * @return {Vector4} this, for chaining 80 | */ 81 | 82 | /** 83 | * Returns the dot product of this vector 84 | * and the specified Vector4. 85 | * 86 | * @method dot 87 | * @return {Number} the dot product 88 | */ 89 | copy: function(otherVec) { 90 | this.x = otherVec.x||0; 91 | this.y = otherVec.y||0; 92 | this.z = otherVec.z||0; 93 | this.w = otherVec.w||0; 94 | return this; 95 | }, 96 | 97 | set: function(x, y, z, w) { 98 | if (typeof x === "object") { 99 | this.x = x.x||0; 100 | this.y = x.y||0; 101 | this.z = x.z||0; 102 | this.w = x.w||0; 103 | } else { 104 | this.x = x||0; 105 | this.y = y||0; 106 | this.z = z||0; 107 | this.w = w||0; 108 | 109 | } 110 | return this; 111 | }, 112 | 113 | add: function(v) { 114 | this.x += v.x; 115 | this.y += v.y; 116 | this.z += v.z; 117 | this.w += v.w; 118 | return this; 119 | }, 120 | 121 | subtract: function(v) { 122 | this.x -= v.x; 123 | this.y -= v.y; 124 | this.z -= v.z; 125 | this.w -= v.w; 126 | return this; 127 | }, 128 | 129 | scale: function(s) { 130 | this.x *= s; 131 | this.y *= s; 132 | this.z *= s; 133 | this.w *= s; 134 | return this; 135 | }, 136 | 137 | 138 | length: function() { 139 | var x = this.x, 140 | y = this.y, 141 | z = this.z, 142 | w = this.w; 143 | return Math.sqrt(x*x + y*y + z*z + w*w); 144 | }, 145 | 146 | lengthSq: function() { 147 | var x = this.x, 148 | y = this.y, 149 | z = this.z, 150 | w = this.w; 151 | return x*x + y*y + z*z + w*w; 152 | }, 153 | 154 | normalize: function() { 155 | var x = this.x, 156 | y = this.y, 157 | z = this.z, 158 | w = this.w; 159 | var len = x*x + y*y + z*z + w*w; 160 | if (len > 0) { 161 | len = 1 / Math.sqrt(len); 162 | this.x = x*len; 163 | this.y = y*len; 164 | this.z = z*len; 165 | this.w = w*len; 166 | } 167 | return this; 168 | }, 169 | 170 | dot: function(v) { 171 | return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; 172 | }, 173 | 174 | lerp: function(v, t) { 175 | var ax = this.x, 176 | ay = this.y, 177 | az = this.z, 178 | aw = this.w; 179 | t = t||0; 180 | this.x = ax + t * (v.x - ax); 181 | this.y = ay + t * (v.y - ay); 182 | this.z = az + t * (v.z - az); 183 | this.w = aw + t * (v.w - aw); 184 | return this; 185 | } 186 | }; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | Vector2: require('./Vector2'), 3 | Vector3: require('./Vector3'), 4 | Vector4: require('./Vector4'), 5 | Matrix3: require('./Matrix3'), 6 | Matrix4: require('./Matrix4'), 7 | Quaternion: require('./Quaternion') 8 | }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vecmath", 3 | "version": "0.1.4", 4 | "description": "Highly optimized vector/matrix math (using objects)", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "browserify": "mkdir -p build && browserify ./lib/index.js -s vecmath -o build/vecmath.js", 8 | "uglify": "uglifyjs build/vecmath.js -o build/vecmath.min.js", 9 | "test": "node test.js" 10 | }, 11 | "author": "", 12 | "license": "BSD-2-Clause", 13 | "repository": { 14 | "type": "git", 15 | "url": "https://github.com/mattdesl/vecmath" 16 | }, 17 | "dependencies": {}, 18 | "devDependencies": { 19 | "browserify": "~3.3.0", 20 | "uglify-js": "~2.4.7" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## no longer maintained 2 | 3 | Although classes and chainable methods can lead to cleaner code and might be easier for rapid prototyping, they ultimately are not as good for module interoperability as plain arrays. For modules I would recommend [gl-vec2](https://github.com/stackgl/gl-vec2), [gl-vec3](https://github.com/stackgl/gl-vec3), [gl-mat4](https://github.com/stackgl/gl-mat4), etc. as it's more modular and generic. Examples: 4 | 5 | https://www.npmjs.org/package/delaunay-triangulate 6 | https://www.npmjs.org/package/simplify-path 7 | https://www.npmjs.org/package/chaikin-smooth 8 | https://www.npmjs.org/package/bezier 9 | https://www.npmjs.org/package/adaptive-bezier-curve 10 | https://www.npmjs.org/package/triangulate-contours 11 | https://www.npmjs.org/package/bunny 12 | https://www.npmjs.org/package/parse-svg-path 13 | 14 | etc. 15 | 16 | -- 17 | 18 | ## vecmath 19 | 20 | This is a small vector module, built with the optimized codebase of [gl-matrix](https://github.com/toji/gl-matrix) but using objects and JavaScript paradigms instead of typed arrays. 21 | 22 | ## install 23 | 24 | With node: 25 | 26 | ``` 27 | npm install vecmath 28 | 29 | ... in code ... 30 | var Matrix4 = require('vecmath').Matrix4; 31 | ``` 32 | 33 | Or you can grab the UMD build from the `build` folder, which will work with RequireJS or a non-module app. 34 | 35 | ## performance 36 | 37 | The reason gl-matrix is so blazingly fast is mostly because its code is highly optimized. It unrolls loops, uses inline code everywhere, and takes advantage of JS variable caching. 38 | 39 | Thanks to optimizations on JS engines (V8, SpiderMonkey, etc), hidden classes and inline caches are _really_ fast nowadays (and will probably only get faster). As you can see in the following benchmarks, class-based Vectors actually outperform array access: 40 | 41 | http://jsperf.com/gl-matrix-vs-objects/4 42 | http://jsperf.com/gl-matrix-vs-vecmath 43 | 44 | It's important to realize that the difference between property and array accessors is negligible for the vast majority of applications, so you shouldn't be sacrificing code readability and maintainability for a change that won't make a dent in the long run. 45 | 46 | ## What about WebGL? 47 | 48 | Using a typed array (if available) for matrices was definitely the right choice of gl-matrix, and so we do the same for WebGL compatibility. Matrix objects have `val`, which is the backing array (Float32Array, or falls back to Array for old browsers). 49 | 50 | ```javascript 51 | var mat = new Matrix4(); 52 | 53 | gl.uniformMatrix4fv(loc, false, mat.val); 54 | ``` 55 | 56 | ## What about new objects? 57 | 58 | Just like in gl-matrix, the API tries to encourage re-using vectors to avoid allocations. So often your code will look like this: 59 | 60 | ```javascript 61 | myVec.add( tmp.set(0, 10, 50) ); 62 | ``` 63 | 64 | However, if you need to create new objects (out of laziness or some other reason), all functions that take a vector/quaternion type will support lightweight objects as well: 65 | 66 | ```javascript 67 | myVec.add({ x:0, y: 10, z: 50 }); 68 | ``` 69 | 70 | These are usually a lot faster to allocate than a Vector class, or a Float32Array (in the case of gl-matrix). 71 | 72 | If you find yourself creating a lot of objects, you should use a Pool to reduce allocations. 73 | 74 | ## Extra features 75 | 76 | The library does its best to stay consistent with the gl-matrix API, but also includes a couple extra features: 77 | 78 | - `Vector3.project(projMatrix)`: this method is useful for projecting a 3D point into 2D space 79 | - `Vector3.unproject(viewport, invProjMatrix)`: useful for *un*projecting a 2D point into 3D space 80 | 81 | ## TODO: 82 | 83 | - Move docs over from gl-matrix 84 | - Add licensing information since most of the code belongs to gl-matrix (???) 85 | - Add mat2 and mat2d 86 | - Test Quaternion + Matrix classes and compare with gl-matrix results 87 | - Further improvements to test suite, using mocha or something 88 | - Make it more modular by placing each class in its own module. Will probably be `math-vector2`, `math-vector3`, etc. since `vector2` is already taken. 89 | 90 | ## License 91 | 92 | MIT 93 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var Vector2 = require('./lib/Vector2'); 2 | var Vector3 = require('./lib/Vector3'); 3 | var Vector4 = require('./lib/Vector4'); 4 | var Quaternion = require('./lib/Quaternion'); 5 | var Matrix3 = require('./lib/Matrix3'); 6 | 7 | var assert = require('assert'); 8 | 9 | var ovec2 = new Vector2(); 10 | var ovec3 = new Vector3(); 11 | var ovec4 = new Vector4(); 12 | var oquat = new Quaternion(); 13 | 14 | var iterations = 10000; 15 | var EPSILON = 0.000001; 16 | 17 | function equalish(a, b) { 18 | return Math.abs(a - b) < EPSILON; 19 | } 20 | 21 | ////// 22 | /// There are lots of improvements we can do here for tests. 23 | 24 | console.log("----- Test Suite -----"); 25 | 26 | var components = ['x', 'y', 'z', 'w']; 27 | var testVals = [-5, -10, 20, 13]; 28 | 29 | function testConstructor(name, ctor, numComponents) { 30 | console.log("-- Testing", name, "constructor") 31 | for (var i=0; i