拷贝three.js代码。

This commit is contained in:
liteng 2018-12-08 07:44:06 +08:00
parent 0d924a7500
commit 17fbac49cf
16 changed files with 6606 additions and 0 deletions

View File

@ -8,6 +8,674 @@ namespace THREE
{
public class Box3
{
public Box3(min, max )
{
this.min = (min !== undefined) ? min : new Vector3(+Infinity, +Infinity, +Infinity);
this.max = (max !== undefined) ? max : new Vector3(-Infinity, -Infinity, -Infinity);
}
isBox3: true,
set: function(min, max )
{
this.min.copy(min);
this.max.copy(max);
return this;
},
setFromArray: function(array )
{
var minX = +Infinity;
var minY = +Infinity;
var minZ = +Infinity;
var maxX = -Infinity;
var maxY = -Infinity;
var maxZ = -Infinity;
for (var i = 0, l = array.length; i < l; i += 3)
{
var x = array[i];
var y = array[i + 1];
var z = array[i + 2];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
if (z > maxZ) maxZ = z;
}
this.min.set(minX, minY, minZ);
this.max.set(maxX, maxY, maxZ);
return this;
},
setFromBufferAttribute: function(attribute )
{
var minX = +Infinity;
var minY = +Infinity;
var minZ = +Infinity;
var maxX = -Infinity;
var maxY = -Infinity;
var maxZ = -Infinity;
for (var i = 0, l = attribute.count; i < l; i++)
{
var x = attribute.getX(i);
var y = attribute.getY(i);
var z = attribute.getZ(i);
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
if (z > maxZ) maxZ = z;
}
this.min.set(minX, minY, minZ);
this.max.set(maxX, maxY, maxZ);
return this;
},
setFromPoints: function(points )
{
this.makeEmpty();
for (var i = 0, il = points.length; i < il; i++)
{
this.expandByPoint(points[i]);
}
return this;
},
setFromCenterAndSize: function()
{
var v1 = new Vector3();
return function setFromCenterAndSize(center, size) {
var halfSize = v1.copy(size).multiplyScalar(0.5);
this.min.copy(center).sub(halfSize);
this.max.copy(center).add(halfSize);
return this;
};
}
(),
setFromObject: function(object )
{
this.makeEmpty();
return this.expandByObject(object);
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(box )
{
this.min.copy(box.min);
this.max.copy(box.max);
return this;
},
makeEmpty: function()
{
this.min.x = this.min.y = this.min.z = +Infinity;
this.max.x = this.max.y = this.max.z = -Infinity;
return this;
},
isEmpty: function()
{
// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
return (this.max.x < this.min.x) || (this.max.y < this.min.y) || (this.max.z < this.min.z);
},
getCenter: function(target )
{
if (target === undefined)
{
console.warn('THREE.Box3: .getCenter() target is now required');
target = new Vector3();
}
return this.isEmpty() ? target.set(0, 0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5);
},
getSize: function(target )
{
if (target === undefined)
{
console.warn('THREE.Box3: .getSize() target is now required');
target = new Vector3();
}
return this.isEmpty() ? target.set(0, 0, 0) : target.subVectors(this.max, this.min);
},
expandByPoint: function(point )
{
this.min.min(point);
this.max.max(point);
return this;
},
expandByVector: function(vector )
{
this.min.sub(vector);
this.max.add(vector);
return this;
},
expandByScalar: function(scalar )
{
this.min.addScalar(-scalar);
this.max.addScalar(scalar);
return this;
},
expandByObject: function()
{
// Computes the world-axis-aligned bounding box of an object (including its children),
// accounting for both the object's, and children's, world transforms
var scope, i, l;
var v1 = new Vector3();
function traverse(node )
{
var geometry = node.geometry;
if (geometry !== undefined)
{
if (geometry.isGeometry)
{
var vertices = geometry.vertices;
for (i = 0, l = vertices.length; i < l; i++)
{
v1.copy(vertices[i]);
v1.applyMatrix4(node.matrixWorld);
scope.expandByPoint(v1);
}
}
else if (geometry.isBufferGeometry)
{
var attribute = geometry.attributes.position;
if (attribute !== undefined)
{
for (i = 0, l = attribute.count; i < l; i++)
{
v1.fromBufferAttribute(attribute, i).applyMatrix4(node.matrixWorld);
scope.expandByPoint(v1);
}
}
}
}
}
return function expandByObject(object) {
scope = this;
object.updateMatrixWorld(true);
object.traverse(traverse);
return this;
};
}
(),
containsPoint: function(point )
{
return point.x < this.min.x || point.x > this.max.x ||
point.y < this.min.y || point.y > this.max.y ||
point.z < this.min.z || point.z > this.max.z ? false : true;
},
containsBox: function(box )
{
return this.min.x <= box.min.x && box.max.x <= this.max.x &&
this.min.y <= box.min.y && box.max.y <= this.max.y &&
this.min.z <= box.min.z && box.max.z <= this.max.z;
},
getParameter: function(point, target )
{
// This can potentially have a divide by zero if the box
// has a size dimension of 0.
if (target === undefined)
{
console.warn('THREE.Box3: .getParameter() target is now required');
target = new Vector3();
}
return target.set(
(point.x - this.min.x) / (this.max.x - this.min.x),
(point.y - this.min.y) / (this.max.y - this.min.y),
(point.z - this.min.z) / (this.max.z - this.min.z)
);
},
intersectsBox: function(box )
{
// using 6 splitting planes to rule out intersections.
return box.max.x < this.min.x || box.min.x > this.max.x ||
box.max.y < this.min.y || box.min.y > this.max.y ||
box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
},
intersectsSphere: (function () {
var closestPoint = new Vector3();
return function intersectsSphere(sphere )
{
// Find the point on the AABB closest to the sphere center.
this.clampPoint(sphere.center, closestPoint);
// If that point is inside the sphere, the AABB and sphere intersect.
return closestPoint.distanceToSquared(sphere.center) <= (sphere.radius * sphere.radius);
};
} )(),
intersectsPlane: function(plane )
{
// We compute the minimum and maximum dot product values. If those values
// are on the same side (back or front) of the plane, then there is no intersection.
var min, max;
if (plane.normal.x > 0)
{
min = plane.normal.x * this.min.x;
max = plane.normal.x * this.max.x;
}
else
{
min = plane.normal.x * this.max.x;
max = plane.normal.x * this.min.x;
}
if (plane.normal.y > 0)
{
min += plane.normal.y * this.min.y;
max += plane.normal.y * this.max.y;
}
else
{
min += plane.normal.y * this.max.y;
max += plane.normal.y * this.min.y;
}
if (plane.normal.z > 0)
{
min += plane.normal.z * this.min.z;
max += plane.normal.z * this.max.z;
}
else
{
min += plane.normal.z * this.max.z;
max += plane.normal.z * this.min.z;
}
return (min <= plane.constant && max >= plane.constant);
},
intersectsTriangle: (function () {
// triangle centered vertices
var v0 = new Vector3();
var v1 = new Vector3();
var v2 = new Vector3();
// triangle edge vectors
var f0 = new Vector3();
var f1 = new Vector3();
var f2 = new Vector3();
var testAxis = new Vector3();
var center = new Vector3();
var extents = new Vector3();
var triangleNormal = new Vector3();
function satForAxes(axes )
{
var i, j;
for (i = 0, j = axes.length - 3; i <= j; i += 3)
{
testAxis.fromArray(axes, i);
// project the aabb onto the seperating axis
var r = extents.x * Math.abs(testAxis.x) + extents.y * Math.abs(testAxis.y) + extents.z * Math.abs(testAxis.z);
// project all 3 vertices of the triangle onto the seperating axis
var p0 = v0.dot(testAxis);
var p1 = v1.dot(testAxis);
var p2 = v2.dot(testAxis);
// actual test, basically see if either of the most extreme of the triangle points intersects r
if (Math.max(-Math.max(p0, p1, p2), Math.min(p0, p1, p2)) > r)
{
// points of the projected triangle are outside the projected half-length of the aabb
// the axis is seperating and we can exit
return false;
}
}
return true;
}
return function intersectsTriangle(triangle )
{
if (this.isEmpty())
{
return false;
}
// compute box center and extents
this.getCenter(center);
extents.subVectors(this.max, center);
// translate triangle to aabb origin
v0.subVectors(triangle.a, center);
v1.subVectors(triangle.b, center);
v2.subVectors(triangle.c, center);
// compute edge vectors for triangle
f0.subVectors(v1, v0);
f1.subVectors(v2, v1);
f2.subVectors(v0, v2);
// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
var axes = [
0, -f0.z, f0.y, 0, -f1.z, f1.y, 0, -f2.z, f2.y,
f0.z, 0, -f0.x, f1.z, 0, -f1.x, f2.z, 0, -f2.x,
-f0.y, f0.x, 0, -f1.y, f1.x, 0, -f2.y, f2.x, 0
];
if (!satForAxes(axes))
{
return false;
}
// test 3 face normals from the aabb
axes = [1, 0, 0, 0, 1, 0, 0, 0, 1];
if (!satForAxes(axes))
{
return false;
}
// finally testing the face normal of the triangle
// use already existing triangle edge vectors here
triangleNormal.crossVectors(f0, f1);
axes = [triangleNormal.x, triangleNormal.y, triangleNormal.z];
return satForAxes(axes);
};
} )(),
clampPoint: function(point, target )
{
if (target === undefined)
{
console.warn('THREE.Box3: .clampPoint() target is now required');
target = new Vector3();
}
return target.copy(point).clamp(this.min, this.max);
},
distanceToPoint: function()
{
var v1 = new Vector3();
return function distanceToPoint(point) {
var clampedPoint = v1.copy(point).clamp(this.min, this.max);
return clampedPoint.sub(point).length();
};
}
(),
getBoundingSphere: function()
{
var v1 = new Vector3();
return function getBoundingSphere(target) {
if (target === undefined)
{
console.warn('THREE.Box3: .getBoundingSphere() target is now required');
target = new Sphere();
}
this.getCenter(target.center);
target.radius = this.getSize(v1).length() * 0.5;
return target;
};
}
(),
intersect: function(box )
{
this.min.max(box.min);
this.max.min(box.max);
// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
if (this.isEmpty()) this.makeEmpty();
return this;
},
union: function(box )
{
this.min.min(box.min);
this.max.max(box.max);
return this;
},
applyMatrix4: function()
{
var points = [
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3(),
new Vector3()
];
return function applyMatrix4(matrix) {
// transform of empty box is an empty box.
if (this.isEmpty()) return this;
// NOTE: I am using a binary pattern to specify all 2^3 combinations below
points[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(matrix); // 000
points[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(matrix); // 001
points[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(matrix); // 010
points[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(matrix); // 011
points[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(matrix); // 100
points[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(matrix); // 101
points[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(matrix); // 110
points[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(matrix); // 111
this.setFromPoints(points);
return this;
};
}
(),
translate: function(offset )
{
this.min.add(offset);
this.max.add(offset);
return this;
},
equals: function(box )
{
return box.min.equals(this.min) && box.max.equals(this.max);
}
}
}

View File

@ -8,6 +8,670 @@ namespace THREE
{
public class Color
{
var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
public Color(r, g, b )
{
if (g === undefined && b === undefined)
{
// r is THREE.Color, hex or string
return this.set(r);
}
return this.setRGB(r, g, b);
}
isColor: true,
r: 1, g: 1, b: 1,
set: function(value )
{
if (value && value.isColor)
{
this.copy(value);
}
else if (typeof value === 'number')
{
this.setHex(value);
}
else if (typeof value === 'string')
{
this.setStyle(value);
}
return this;
},
setScalar: function(scalar )
{
this.r = scalar;
this.g = scalar;
this.b = scalar;
return this;
},
setHex: function(hex )
{
hex = Math.floor(hex);
this.r = (hex >> 16 & 255) / 255;
this.g = (hex >> 8 & 255) / 255;
this.b = (hex & 255) / 255;
return this;
},
setRGB: function(r, g, b )
{
this.r = r;
this.g = g;
this.b = b;
return this;
},
setHSL: function()
{
function hue2rgb(p, q, t )
{
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t);
return p;
}
return function setHSL(h, s, l) {
// h,s,l ranges are in 0.0 - 1.0
h = _Math.euclideanModulo(h, 1);
s = _Math.clamp(s, 0, 1);
l = _Math.clamp(l, 0, 1);
if (s === 0)
{
this.r = this.g = this.b = l;
}
else
{
var p = l <= 0.5 ? l * (1 + s) : l + s - (l * s);
var q = (2 * l) - p;
this.r = hue2rgb(q, p, h + 1 / 3);
this.g = hue2rgb(q, p, h);
this.b = hue2rgb(q, p, h - 1 / 3);
}
return this;
};
}
(),
setStyle: function(style )
{
function handleAlpha(string )
{
if (string === undefined) return;
if (parseFloat(string) < 1)
{
console.warn('THREE.Color: Alpha component of ' + style + ' will be ignored.');
}
}
var m;
if (m = /^ ((?: rgb | hsl)a ?)\(\s * ([^\)]*)\)/.exec(style) ) {
// rgb / hsl
var color;
var name = m[1];
var components = m[2];
switch (name)
{
case 'rgb':
case 'rgba':
if (color = /^ (\d +)\s *,\s * (\d +)\s *,\s * (\d +)\s * (,\s * ([0 - 9] *\.?[0-9]+)\s*)?$/.exec(components ) ) {
// rgb(255,0,0) rgba(255,0,0,0.5)
this.r = Math.min( 255, parseInt(color[1], 10 ) ) / 255;
this.g = Math.min( 255, parseInt(color[2], 10 ) ) / 255;
this.b = Math.min( 255, parseInt(color[3], 10 ) ) / 255;
handleAlpha(color[5] );
return this;
}
if (color = /^(\d+)\%\s*,\s* (\d+)\%\s*,\s* (\d+)\%\s* (,\s* ([0 - 9]*\.?[0 - 9]+)\s*)?$/.exec(components ) ) {
// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
this.r = Math.min(100, parseInt(color[1], 10)) / 100;
this.g = Math.min(100, parseInt(color[2], 10)) / 100;
this.b = Math.min(100, parseInt(color[3], 10)) / 100;
handleAlpha(color[5] );
return this;
}
break;
case 'hsl':
case 'hsla':
if (color = /^([0 - 9]*\.?[0 - 9]+)\s*,\s* (\d+)\%\s*,\s* (\d+)\%\s* (,\s* ([0 - 9]*\.?[0 - 9]+)\s*)?$/.exec(components ) ) {
// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
var h = parseFloat(color[1]) / 360;
var s = parseInt(color[2], 10) / 100;
var l = parseInt(color[3], 10) / 100;
handleAlpha(color[5] );
return this.setHSL(h, s, l);
}
break;
}
} else if (m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
// hex color
var hex = m[1];
var size = hex.length;
if (size === 3 ) {
// #ff0
this.r = parseInt(hex.charAt(0) + hex.charAt(0), 16) / 255;
this.g = parseInt(hex.charAt(1) + hex.charAt(1), 16) / 255;
this.b = parseInt(hex.charAt(2) + hex.charAt(2), 16) / 255;
return this;
} else if (size === 6 ) {
// #ff0000
this.r = parseInt(hex.charAt(0) + hex.charAt(1), 16) / 255;
this.g = parseInt(hex.charAt(2) + hex.charAt(3), 16) / 255;
this.b = parseInt(hex.charAt(4) + hex.charAt(5), 16) / 255;
return this;
}
}
if (style && style.length > 0 ) {
// color keywords
var hex = ColorKeywords[style];
if (hex !== undefined ) {
// red
this.setHex(hex );
} else {
// unknown color
console.warn( 'THREE.Color: Unknown color ' + style );
}
}
return this;
},
clone: function()
{
return new this.constructor(this.r, this.g, this.b);
},
copy: function(color )
{
this.r = color.r;
this.g = color.g;
this.b = color.b;
return this;
},
copyGammaToLinear: function(color, gammaFactor )
{
if (gammaFactor === undefined) gammaFactor = 2.0;
this.r = Math.pow(color.r, gammaFactor);
this.g = Math.pow(color.g, gammaFactor);
this.b = Math.pow(color.b, gammaFactor);
return this;
},
copyLinearToGamma: function(color, gammaFactor )
{
if (gammaFactor === undefined) gammaFactor = 2.0;
var safeInverse = (gammaFactor > 0) ? (1.0 / gammaFactor) : 1.0;
this.r = Math.pow(color.r, safeInverse);
this.g = Math.pow(color.g, safeInverse);
this.b = Math.pow(color.b, safeInverse);
return this;
},
convertGammaToLinear: function(gammaFactor )
{
this.copyGammaToLinear(this, gammaFactor);
return this;
},
convertLinearToGamma: function(gammaFactor )
{
this.copyLinearToGamma(this, gammaFactor);
return this;
},
copySRGBToLinear: function()
{
function SRGBToLinear(c )
{
return (c < 0.04045) ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
}
return function copySRGBToLinear(color) {
this.r = SRGBToLinear(color.r);
this.g = SRGBToLinear(color.g);
this.b = SRGBToLinear(color.b);
return this;
};
}
(),
copyLinearToSRGB: function()
{
function LinearToSRGB(c )
{
return (c < 0.0031308) ? c * 12.92 : 1.055 * (Math.pow(c, 0.41666)) - 0.055;
}
return function copyLinearToSRGB(color) {
this.r = LinearToSRGB(color.r);
this.g = LinearToSRGB(color.g);
this.b = LinearToSRGB(color.b);
return this;
};
}
(),
convertSRGBToLinear: function()
{
this.copySRGBToLinear(this);
return this;
},
convertLinearToSRGB: function()
{
this.copyLinearToSRGB(this);
return this;
},
getHex: function()
{
return (this.r * 255) << 16 ^ (this.g * 255) << 8 ^ (this.b * 255) << 0;
},
getHexString: function()
{
return ('000000' + this.getHex().toString(16)).slice(-6);
},
getHSL: function(target )
{
// h,s,l ranges are in 0.0 - 1.0
if (target === undefined)
{
console.warn('THREE.Color: .getHSL() target is now required');
target = { h: 0, s: 0, l: 0 };
}
var r = this.r, g = this.g, b = this.b;
var max = Math.max(r, g, b);
var min = Math.min(r, g, b);
var hue, saturation;
var lightness = (min + max) / 2.0;
if (min === max)
{
hue = 0;
saturation = 0;
}
else
{
var delta = max - min;
saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
switch (max)
{
case r: hue = (g - b) / delta + (g < b ? 6 : 0); break;
case g: hue = (b - r) / delta + 2; break;
case b: hue = (r - g) / delta + 4; break;
}
hue /= 6;
}
target.h = hue;
target.s = saturation;
target.l = lightness;
return target;
},
getStyle: function()
{
return 'rgb(' + ((this.r * 255) | 0) + ',' + ((this.g * 255) | 0) + ',' + ((this.b * 255) | 0) + ')';
},
offsetHSL: function()
{
var hsl = { };
return function(h, s, l) {
this.getHSL(hsl);
hsl.h += h; hsl.s += s; hsl.l += l;
this.setHSL(hsl.h, hsl.s, hsl.l);
return this;
};
}
(),
add: function(color )
{
this.r += color.r;
this.g += color.g;
this.b += color.b;
return this;
},
addColors: function(color1, color2 )
{
this.r = color1.r + color2.r;
this.g = color1.g + color2.g;
this.b = color1.b + color2.b;
return this;
},
addScalar: function(s )
{
this.r += s;
this.g += s;
this.b += s;
return this;
},
sub: function(color )
{
this.r = Math.max(0, this.r - color.r);
this.g = Math.max(0, this.g - color.g);
this.b = Math.max(0, this.b - color.b);
return this;
},
multiply: function(color )
{
this.r *= color.r;
this.g *= color.g;
this.b *= color.b;
return this;
},
multiplyScalar: function(s )
{
this.r *= s;
this.g *= s;
this.b *= s;
return this;
},
lerp: function(color, alpha )
{
this.r += (color.r - this.r) * alpha;
this.g += (color.g - this.g) * alpha;
this.b += (color.b - this.b) * alpha;
return this;
},
lerpHSL: function()
{
var hslA = { h: 0, s: 0, l: 0 };
var hslB = { h: 0, s: 0, l: 0 };
return function lerpHSL(color, alpha )
{
this.getHSL(hslA);
color.getHSL(hslB);
var h = _Math.lerp(hslA.h, hslB.h, alpha);
var s = _Math.lerp(hslA.s, hslB.s, alpha);
var l = _Math.lerp(hslA.l, hslB.l, alpha);
this.setHSL(h, s, l);
return this;
};
}(),
equals: function(c )
{
return (c.r === this.r) && (c.g === this.g) && (c.b === this.b);
},
fromArray: function(array, offset )
{
if (offset === undefined) offset = 0;
this.r = array[offset];
this.g = array[offset + 1];
this.b = array[offset + 2];
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
array[offset] = this.r;
array[offset + 1] = this.g;
array[offset + 2] = this.b;
return array;
},
toJSON: function()
{
return this.getHex();
}
}
}

View File

@ -8,6 +8,62 @@ namespace THREE
{
public class Cylindrical
{
function Cylindrical(radius, theta, y )
{
this.radius = (radius !== undefined) ? radius : 1.0; // distance from the origin to a point in the x-z plane
this.theta = (theta !== undefined) ? theta : 0; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis
this.y = (y !== undefined) ? y : 0; // height above the x-z plane
return this;
}
set: function(radius, theta, y )
{
this.radius = radius;
this.theta = theta;
this.y = y;
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(other )
{
this.radius = other.radius;
this.theta = other.theta;
this.y = other.y;
return this;
},
setFromVector3: function(v )
{
return this.setFromCartesianCoords(v.x, v.y, v.z);
},
setFromCartesianCoords: function(x, y, z )
{
this.radius = Math.sqrt(x * x + z * z);
this.theta = Math.atan2(x, z);
this.y = y;
return this;
}
}
}

View File

@ -8,6 +8,396 @@ namespace THREE
{
public class Euler
{
Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
Euler.DefaultOrder = 'XYZ';
function Euler(x, y, z, order )
{
this._x = x || 0;
this._y = y || 0;
this._z = z || 0;
this._order = order || Euler.DefaultOrder;
}
x: {
get: function()
{
return this._x;
},
set: function(value )
{
this._x = value;
this.onChangeCallback();
}
},
y: {
get: function()
{
return this._y;
},
set: function(value )
{
this._y = value;
this.onChangeCallback();
}
},
z: {
get: function()
{
return this._z;
},
set: function(value )
{
this._z = value;
this.onChangeCallback();
}
},
order: {
get: function()
{
return this._order;
},
set: function(value )
{
this._order = value;
this.onChangeCallback();
}
}
} );
Object.assign(Euler.prototype, {
isEuler: true,
set: function(x, y, z, order )
{
this._x = x;
this._y = y;
this._z = z;
this._order = order || this._order;
this.onChangeCallback();
return this;
},
clone: function()
{
return new this.constructor(this._x, this._y, this._z, this._order);
},
copy: function(euler )
{
this._x = euler._x;
this._y = euler._y;
this._z = euler._z;
this._order = euler._order;
this.onChangeCallback();
return this;
},
setFromRotationMatrix: function(m, order, update )
{
var clamp = _Math.clamp;
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var te = m.elements;
var m11 = te[0], m12 = te[4], m13 = te[8];
var m21 = te[1], m22 = te[5], m23 = te[9];
var m31 = te[2], m32 = te[6], m33 = te[10];
order = order || this._order;
if (order === 'XYZ')
{
this._y = Math.asin(clamp(m13, -1, 1));
if (Math.abs(m13) < 0.99999)
{
this._x = Math.atan2(-m23, m33);
this._z = Math.atan2(-m12, m11);
}
else
{
this._x = Math.atan2(m32, m22);
this._z = 0;
}
}
else if (order === 'YXZ')
{
this._x = Math.asin(-clamp(m23, -1, 1));
if (Math.abs(m23) < 0.99999)
{
this._y = Math.atan2(m13, m33);
this._z = Math.atan2(m21, m22);
}
else
{
this._y = Math.atan2(-m31, m11);
this._z = 0;
}
}
else if (order === 'ZXY')
{
this._x = Math.asin(clamp(m32, -1, 1));
if (Math.abs(m32) < 0.99999)
{
this._y = Math.atan2(-m31, m33);
this._z = Math.atan2(-m12, m22);
}
else
{
this._y = 0;
this._z = Math.atan2(m21, m11);
}
}
else if (order === 'ZYX')
{
this._y = Math.asin(-clamp(m31, -1, 1));
if (Math.abs(m31) < 0.99999)
{
this._x = Math.atan2(m32, m33);
this._z = Math.atan2(m21, m11);
}
else
{
this._x = 0;
this._z = Math.atan2(-m12, m22);
}
}
else if (order === 'YZX')
{
this._z = Math.asin(clamp(m21, -1, 1));
if (Math.abs(m21) < 0.99999)
{
this._x = Math.atan2(-m23, m22);
this._y = Math.atan2(-m31, m11);
}
else
{
this._x = 0;
this._y = Math.atan2(m13, m33);
}
}
else if (order === 'XZY')
{
this._z = Math.asin(-clamp(m12, -1, 1));
if (Math.abs(m12) < 0.99999)
{
this._x = Math.atan2(m32, m22);
this._y = Math.atan2(m13, m11);
}
else
{
this._x = Math.atan2(-m23, m33);
this._y = 0;
}
}
else
{
console.warn('THREE.Euler: .setFromRotationMatrix() given unsupported order: ' + order);
}
this._order = order;
if (update !== false) this.onChangeCallback();
return this;
},
setFromQuaternion: function()
{
var matrix = new Matrix4();
return function setFromQuaternion(q, order, update) {
matrix.makeRotationFromQuaternion(q);
return this.setFromRotationMatrix(matrix, order, update);
};
}
(),
setFromVector3: function(v, order )
{
return this.set(v.x, v.y, v.z, order || this._order);
},
reorder: function()
{
// WARNING: this discards revolution information -bhouston
var q = new Quaternion();
return function reorder(newOrder) {
q.setFromEuler(this);
return this.setFromQuaternion(q, newOrder);
};
}
(),
equals: function(euler )
{
return (euler._x === this._x) && (euler._y === this._y) && (euler._z === this._z) && (euler._order === this._order);
},
fromArray: function(array )
{
this._x = array[0];
this._y = array[1];
this._z = array[2];
if (array[3] !== undefined) this._order = array[3];
this.onChangeCallback();
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
array[offset] = this._x;
array[offset + 1] = this._y;
array[offset + 2] = this._z;
array[offset + 3] = this._order;
return array;
},
toVector3: function(optionalResult )
{
if (optionalResult)
{
return optionalResult.set(this._x, this._y, this._z);
}
else
{
return new Vector3(this._x, this._y, this._z);
}
},
onChange: function(callback )
{
this.onChangeCallback = callback;
return this;
},
onChangeCallback: function() { }
}
}

View File

@ -8,6 +8,202 @@ namespace THREE
{
public class Frustum
{
function Frustum(p0, p1, p2, p3, p4, p5 )
{
this.planes = [
(p0 !== undefined) ? p0 : new Plane(),
(p1 !== undefined) ? p1 : new Plane(),
(p2 !== undefined) ? p2 : new Plane(),
(p3 !== undefined) ? p3 : new Plane(),
(p4 !== undefined) ? p4 : new Plane(),
(p5 !== undefined) ? p5 : new Plane()
];
}
set: function(p0, p1, p2, p3, p4, p5 )
{
var planes = this.planes;
planes[0].copy(p0);
planes[1].copy(p1);
planes[2].copy(p2);
planes[3].copy(p3);
planes[4].copy(p4);
planes[5].copy(p5);
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(frustum )
{
var planes = this.planes;
for (var i = 0; i < 6; i++)
{
planes[i].copy(frustum.planes[i]);
}
return this;
},
setFromMatrix: function(m )
{
var planes = this.planes;
var me = m.elements;
var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];
planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize();
planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize();
planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize();
planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize();
planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize();
planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize();
return this;
},
intersectsObject: function()
{
var sphere = new Sphere();
return function intersectsObject(object) {
var geometry = object.geometry;
if (geometry.boundingSphere === null)
geometry.computeBoundingSphere();
sphere.copy(geometry.boundingSphere)
.applyMatrix4(object.matrixWorld);
return this.intersectsSphere(sphere);
};
}
(),
intersectsSprite: function()
{
var sphere = new Sphere();
return function intersectsSprite(sprite) {
sphere.center.set(0, 0, 0);
sphere.radius = 0.7071067811865476;
sphere.applyMatrix4(sprite.matrixWorld);
return this.intersectsSphere(sphere);
};
}
(),
intersectsSphere: function(sphere )
{
var planes = this.planes;
var center = sphere.center;
var negRadius = -sphere.radius;
for (var i = 0; i < 6; i++)
{
var distance = planes[i].distanceToPoint(center);
if (distance < negRadius)
{
return false;
}
}
return true;
},
intersectsBox: function()
{
var p = new Vector3();
return function intersectsBox(box) {
var planes = this.planes;
for (var i = 0; i < 6; i++)
{
var plane = planes[i];
// corner at max distance
p.x = plane.normal.x > 0 ? box.max.x : box.min.x;
p.y = plane.normal.y > 0 ? box.max.y : box.min.y;
p.z = plane.normal.z > 0 ? box.max.z : box.min.z;
if (plane.distanceToPoint(p) < 0)
{
return false;
}
}
return true;
};
}
(),
containsPoint: function(point )
{
var planes = this.planes;
for (var i = 0; i < 6; i++)
{
if (planes[i].distanceToPoint(point) < 0)
{
return false;
}
}
return true;
}
}
}

View File

@ -8,6 +8,255 @@ namespace THREE
{
public class Interpolant
{
function Interpolant(parameterPositions, sampleValues, sampleSize, resultBuffer )
{
this.parameterPositions = parameterPositions;
this._cachedIndex = 0;
this.resultBuffer = resultBuffer !== undefined ?
resultBuffer : new sampleValues.constructor(sampleSize);
this.sampleValues = sampleValues;
this.valueSize = sampleSize;
}
evaluate: function(t )
{
var pp = this.parameterPositions,
i1 = this._cachedIndex,
t1 = pp[i1],
t0 = pp[i1 - 1];
validate_interval:
{
seek:
{
var right;
linear_scan:
{
//- See http://jsperf.com/comparison-to-undefined/3
//- slower code:
//-
//- if ( t >= t1 || t1 === undefined ) {
forward_scan: if (!(t < t1))
{
for (var giveUpAt = i1 + 2; ;)
{
if (t1 === undefined)
{
if (t < t0) break forward_scan;
// after end
i1 = pp.length;
this._cachedIndex = i1;
return this.afterEnd_(i1 - 1, t, t0);
}
if (i1 === giveUpAt) break; // this loop
t0 = t1;
t1 = pp[++i1];
if (t < t1)
{
// we have arrived at the sought interval
break seek;
}
}
// prepare binary search on the right side of the index
right = pp.length;
break linear_scan;
}
//- slower code:
//- if ( t < t0 || t0 === undefined ) {
if (!(t >= t0))
{
// looping?
var t1global = pp[1];
if (t < t1global)
{
i1 = 2; // + 1, using the scan for the details
t0 = t1global;
}
// linear reverse scan
for (var giveUpAt = i1 - 2; ;)
{
if (t0 === undefined)
{
// before start
this._cachedIndex = 0;
return this.beforeStart_(0, t, t1);
}
if (i1 === giveUpAt) break; // this loop
t1 = t0;
t0 = pp[--i1 - 1];
if (t >= t0)
{
// we have arrived at the sought interval
break seek;
}
}
// prepare binary search on the left side of the index
right = i1;
i1 = 0;
break linear_scan;
}
// the interval is valid
break validate_interval;
} // linear scan
// binary search
while (i1 < right)
{
var mid = (i1 + right) >>> 1;
if (t < pp[mid])
{
right = mid;
}
else
{
i1 = mid + 1;
}
}
t1 = pp[i1];
t0 = pp[i1 - 1];
// check boundary cases, again
if (t0 === undefined)
{
this._cachedIndex = 0;
return this.beforeStart_(0, t, t1);
}
if (t1 === undefined)
{
i1 = pp.length;
this._cachedIndex = i1;
return this.afterEnd_(i1 - 1, t0, t);
}
} // seek
this._cachedIndex = i1;
this.intervalChanged_(i1, t0, t1);
} // validate_interval
return this.interpolate_(i1, t0, t, t1);
},
settings: null, // optional, subclass-specific settings structure
// Note: The indirection allows central control of many interpolants.
// --- Protected interface
DefaultSettings_: {},
getSettings_: function()
{
return this.settings || this.DefaultSettings_;
},
copySampleValue_: function(index )
{
// copies a sample value to the result buffer
var result = this.resultBuffer,
values = this.sampleValues,
stride = this.valueSize,
offset = index * stride;
for (var i = 0; i !== stride; ++i)
{
result[i] = values[offset + i];
}
return result;
},
// Template methods for derived classes:
interpolate_: function( /* i1, t0, t, t1 */ )
{
throw new Error('call to abstract method');
// implementations shall return this.resultBuffer
},
intervalChanged_: function( /* i1, t0, t1 */ )
{
// empty
}
//( 0, t, t0 ), returns this.resultBuffer
beforeStart_: Interpolant.prototype.copySampleValue_,
//( N-1, tN-1, t ), returns this.resultBuffer
afterEnd_: Interpolant.prototype.copySampleValue_,
}
}

View File

@ -8,6 +8,162 @@ namespace THREE
{
public class Line3
{
function Line3(start, end )
{
this.start = (start !== undefined) ? start : new Vector3();
this.end = (end !== undefined) ? end : new Vector3();
}
set: function(start, end )
{
this.start.copy(start);
this.end.copy(end);
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(line )
{
this.start.copy(line.start);
this.end.copy(line.end);
return this;
},
getCenter: function(target )
{
if (target === undefined)
{
console.warn('THREE.Line3: .getCenter() target is now required');
target = new Vector3();
}
return target.addVectors(this.start, this.end).multiplyScalar(0.5);
},
delta: function(target )
{
if (target === undefined)
{
console.warn('THREE.Line3: .delta() target is now required');
target = new Vector3();
}
return target.subVectors(this.end, this.start);
},
distanceSq: function()
{
return this.start.distanceToSquared(this.end);
},
distance: function()
{
return this.start.distanceTo(this.end);
},
at: function(t, target )
{
if (target === undefined)
{
console.warn('THREE.Line3: .at() target is now required');
target = new Vector3();
}
return this.delta(target).multiplyScalar(t).add(this.start);
},
closestPointToPointParameter: function()
{
var startP = new Vector3();
var startEnd = new Vector3();
return function closestPointToPointParameter(point, clampToLine) {
startP.subVectors(point, this.start);
startEnd.subVectors(this.end, this.start);
var startEnd2 = startEnd.dot(startEnd);
var startEnd_startP = startEnd.dot(startP);
var t = startEnd_startP / startEnd2;
if (clampToLine)
{
t = _Math.clamp(t, 0, 1);
}
return t;
};
}
(),
closestPointToPoint: function(point, clampToLine, target )
{
var t = this.closestPointToPointParameter(point, clampToLine);
if (target === undefined)
{
console.warn('THREE.Line3: .closestPointToPoint() target is now required');
target = new Vector3();
}
return this.delta(target).multiplyScalar(t).add(this.start);
},
applyMatrix4: function(matrix )
{
this.start.applyMatrix4(matrix);
this.end.applyMatrix4(matrix);
return this;
},
equals: function(line )
{
return line.start.equals(this.start) && line.end.equals(this.end);
}
}
}

View File

@ -18,5 +18,391 @@ namespace THREE
0, 0, 1
};
}
isMatrix3: true,
set: function(n11, n12, n13, n21, n22, n23, n31, n32, n33 )
{
var te = this.elements;
te[0] = n11; te[1] = n21; te[2] = n31;
te[3] = n12; te[4] = n22; te[5] = n32;
te[6] = n13; te[7] = n23; te[8] = n33;
return this;
},
identity: function()
{
this.set(
1, 0, 0,
0, 1, 0,
0, 0, 1
);
return this;
},
clone: function()
{
return new this.constructor().fromArray(this.elements);
},
copy: function(m )
{
var te = this.elements;
var me = m.elements;
te[0] = me[0]; te[1] = me[1]; te[2] = me[2];
te[3] = me[3]; te[4] = me[4]; te[5] = me[5];
te[6] = me[6]; te[7] = me[7]; te[8] = me[8];
return this;
},
setFromMatrix4: function(m )
{
var me = m.elements;
this.set(
me[0], me[4], me[8],
me[1], me[5], me[9],
me[2], me[6], me[10]
);
return this;
},
applyToBufferAttribute: function()
{
var v1 = new Vector3();
return function applyToBufferAttribute(attribute) {
for (var i = 0, l = attribute.count; i < l; i++)
{
v1.x = attribute.getX(i);
v1.y = attribute.getY(i);
v1.z = attribute.getZ(i);
v1.applyMatrix3(this);
attribute.setXYZ(i, v1.x, v1.y, v1.z);
}
return attribute;
};
}
(),
multiply: function(m )
{
return this.multiplyMatrices(this, m);
},
premultiply: function(m )
{
return this.multiplyMatrices(m, this);
},
multiplyMatrices: function(a, b )
{
var ae = a.elements;
var be = b.elements;
var te = this.elements;
var a11 = ae[0], a12 = ae[3], a13 = ae[6];
var a21 = ae[1], a22 = ae[4], a23 = ae[7];
var a31 = ae[2], a32 = ae[5], a33 = ae[8];
var b11 = be[0], b12 = be[3], b13 = be[6];
var b21 = be[1], b22 = be[4], b23 = be[7];
var b31 = be[2], b32 = be[5], b33 = be[8];
te[0] = a11 * b11 + a12 * b21 + a13 * b31;
te[3] = a11 * b12 + a12 * b22 + a13 * b32;
te[6] = a11 * b13 + a12 * b23 + a13 * b33;
te[1] = a21 * b11 + a22 * b21 + a23 * b31;
te[4] = a21 * b12 + a22 * b22 + a23 * b32;
te[7] = a21 * b13 + a22 * b23 + a23 * b33;
te[2] = a31 * b11 + a32 * b21 + a33 * b31;
te[5] = a31 * b12 + a32 * b22 + a33 * b32;
te[8] = a31 * b13 + a32 * b23 + a33 * b33;
return this;
},
multiplyScalar: function(s )
{
var te = this.elements;
te[0] *= s; te[3] *= s; te[6] *= s;
te[1] *= s; te[4] *= s; te[7] *= s;
te[2] *= s; te[5] *= s; te[8] *= s;
return this;
},
determinant: function()
{
var te = this.elements;
var a = te[0], b = te[1], c = te[2],
d = te[3], e = te[4], f = te[5],
g = te[6], h = te[7], i = te[8];
return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
},
getInverse: function(matrix, throwOnDegenerate )
{
if (matrix && matrix.isMatrix4)
{
console.error("THREE.Matrix3: .getInverse() no longer takes a Matrix4 argument.");
}
var me = matrix.elements,
te = this.elements,
n11 = me[0], n21 = me[1], n31 = me[2],
n12 = me[3], n22 = me[4], n32 = me[5],
n13 = me[6], n23 = me[7], n33 = me[8],
t11 = n33 * n22 - n32 * n23,
t12 = n32 * n13 - n33 * n12,
t13 = n23 * n12 - n22 * n13,
det = n11 * t11 + n21 * t12 + n31 * t13;
if (det === 0)
{
var msg = "THREE.Matrix3: .getInverse() can't invert matrix, determinant is 0";
if (throwOnDegenerate === true)
{
throw new Error(msg);
}
else
{
console.warn(msg);
}
return this.identity();
}
var detInv = 1 / det;
te[0] = t11 * detInv;
te[1] = (n31 * n23 - n33 * n21) * detInv;
te[2] = (n32 * n21 - n31 * n22) * detInv;
te[3] = t12 * detInv;
te[4] = (n33 * n11 - n31 * n13) * detInv;
te[5] = (n31 * n12 - n32 * n11) * detInv;
te[6] = t13 * detInv;
te[7] = (n21 * n13 - n23 * n11) * detInv;
te[8] = (n22 * n11 - n21 * n12) * detInv;
return this;
},
transpose: function()
{
var tmp, m = this.elements;
tmp = m[1]; m[1] = m[3]; m[3] = tmp;
tmp = m[2]; m[2] = m[6]; m[6] = tmp;
tmp = m[5]; m[5] = m[7]; m[7] = tmp;
return this;
},
getNormalMatrix: function(matrix4 )
{
return this.setFromMatrix4(matrix4).getInverse(this).transpose();
},
transposeIntoArray: function(r )
{
var m = this.elements;
r[0] = m[0];
r[1] = m[3];
r[2] = m[6];
r[3] = m[1];
r[4] = m[4];
r[5] = m[7];
r[6] = m[2];
r[7] = m[5];
r[8] = m[8];
return this;
},
setUvTransform: function(tx, ty, sx, sy, rotation, cx, cy )
{
var c = Math.cos(rotation);
var s = Math.sin(rotation);
this.set(
sx * c, sx * s, -sx * (c * cx + s * cy) + cx + tx,
-sy * s, sy * c, -sy * (-s * cx + c * cy) + cy + ty,
0, 0, 1
);
},
scale: function(sx, sy )
{
var te = this.elements;
te[0] *= sx; te[3] *= sx; te[6] *= sx;
te[1] *= sy; te[4] *= sy; te[7] *= sy;
return this;
},
rotate: function(theta )
{
var c = Math.cos(theta);
var s = Math.sin(theta);
var te = this.elements;
var a11 = te[0], a12 = te[3], a13 = te[6];
var a21 = te[1], a22 = te[4], a23 = te[7];
te[0] = c * a11 + s * a21;
te[3] = c * a12 + s * a22;
te[6] = c * a13 + s * a23;
te[1] = -s * a11 + c * a21;
te[4] = -s * a12 + c * a22;
te[7] = -s * a13 + c * a23;
return this;
},
translate: function(tx, ty )
{
var te = this.elements;
te[0] += tx * te[2]; te[3] += tx * te[5]; te[6] += tx * te[8];
te[1] += ty * te[2]; te[4] += ty * te[5]; te[7] += ty * te[8];
return this;
},
equals: function(matrix )
{
var te = this.elements;
var me = matrix.elements;
for (var i = 0; i < 9; i++)
{
if (te[i] !== me[i]) return false;
}
return true;
},
fromArray: function(array, offset )
{
if (offset === undefined) offset = 0;
for (var i = 0; i < 9; i++)
{
this.elements[i] = array[i + offset];
}
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
var te = this.elements;
array[offset] = te[0];
array[offset + 1] = te[1];
array[offset + 2] = te[2];
array[offset + 3] = te[3];
array[offset + 4] = te[4];
array[offset + 5] = te[5];
array[offset + 6] = te[6];
array[offset + 7] = te[7];
array[offset + 8] = te[8];
return array;
}
}
}

View File

@ -19,5 +19,970 @@ namespace THREE
0, 0, 0, 1
};
}
isMatrix4: true,
set: function(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 )
{
var te = this.elements;
te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14;
te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24;
te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34;
te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44;
return this;
},
identity: function()
{
this.set(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
},
clone: function()
{
return new Matrix4().fromArray(this.elements);
},
copy: function(m )
{
var te = this.elements;
var me = m.elements;
te[0] = me[0]; te[1] = me[1]; te[2] = me[2]; te[3] = me[3];
te[4] = me[4]; te[5] = me[5]; te[6] = me[6]; te[7] = me[7];
te[8] = me[8]; te[9] = me[9]; te[10] = me[10]; te[11] = me[11];
te[12] = me[12]; te[13] = me[13]; te[14] = me[14]; te[15] = me[15];
return this;
},
copyPosition: function(m )
{
var te = this.elements, me = m.elements;
te[12] = me[12];
te[13] = me[13];
te[14] = me[14];
return this;
},
extractBasis: function(xAxis, yAxis, zAxis )
{
xAxis.setFromMatrixColumn(this, 0);
yAxis.setFromMatrixColumn(this, 1);
zAxis.setFromMatrixColumn(this, 2);
return this;
},
makeBasis: function(xAxis, yAxis, zAxis )
{
this.set(
xAxis.x, yAxis.x, zAxis.x, 0,
xAxis.y, yAxis.y, zAxis.y, 0,
xAxis.z, yAxis.z, zAxis.z, 0,
0, 0, 0, 1
);
return this;
},
extractRotation: function()
{
var v1 = new Vector3();
return function extractRotation(m) {
// this method does not support reflection matrices
var te = this.elements;
var me = m.elements;
var scaleX = 1 / v1.setFromMatrixColumn(m, 0).length();
var scaleY = 1 / v1.setFromMatrixColumn(m, 1).length();
var scaleZ = 1 / v1.setFromMatrixColumn(m, 2).length();
te[0] = me[0] * scaleX;
te[1] = me[1] * scaleX;
te[2] = me[2] * scaleX;
te[3] = 0;
te[4] = me[4] * scaleY;
te[5] = me[5] * scaleY;
te[6] = me[6] * scaleY;
te[7] = 0;
te[8] = me[8] * scaleZ;
te[9] = me[9] * scaleZ;
te[10] = me[10] * scaleZ;
te[11] = 0;
te[12] = 0;
te[13] = 0;
te[14] = 0;
te[15] = 1;
return this;
};
}
(),
makeRotationFromEuler: function(euler )
{
if (!(euler && euler.isEuler))
{
console.error('THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.');
}
var te = this.elements;
var x = euler.x, y = euler.y, z = euler.z;
var a = Math.cos(x), b = Math.sin(x);
var c = Math.cos(y), d = Math.sin(y);
var e = Math.cos(z), f = Math.sin(z);
if (euler.order === 'XYZ')
{
var ae = a * e, af = a * f, be = b * e, bf = b * f;
te[0] = c * e;
te[4] = -c * f;
te[8] = d;
te[1] = af + be * d;
te[5] = ae - bf * d;
te[9] = -b * c;
te[2] = bf - ae * d;
te[6] = be + af * d;
te[10] = a * c;
}
else if (euler.order === 'YXZ')
{
var ce = c * e, cf = c * f, de = d * e, df = d * f;
te[0] = ce + df * b;
te[4] = de * b - cf;
te[8] = a * d;
te[1] = a * f;
te[5] = a * e;
te[9] = -b;
te[2] = cf * b - de;
te[6] = df + ce * b;
te[10] = a * c;
}
else if (euler.order === 'ZXY')
{
var ce = c * e, cf = c * f, de = d * e, df = d * f;
te[0] = ce - df * b;
te[4] = -a * f;
te[8] = de + cf * b;
te[1] = cf + de * b;
te[5] = a * e;
te[9] = df - ce * b;
te[2] = -a * d;
te[6] = b;
te[10] = a * c;
}
else if (euler.order === 'ZYX')
{
var ae = a * e, af = a * f, be = b * e, bf = b * f;
te[0] = c * e;
te[4] = be * d - af;
te[8] = ae * d + bf;
te[1] = c * f;
te[5] = bf * d + ae;
te[9] = af * d - be;
te[2] = -d;
te[6] = b * c;
te[10] = a * c;
}
else if (euler.order === 'YZX')
{
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
te[0] = c * e;
te[4] = bd - ac * f;
te[8] = bc * f + ad;
te[1] = f;
te[5] = a * e;
te[9] = -b * e;
te[2] = -d * e;
te[6] = ad * f + bc;
te[10] = ac - bd * f;
}
else if (euler.order === 'XZY')
{
var ac = a * c, ad = a * d, bc = b * c, bd = b * d;
te[0] = c * e;
te[4] = -f;
te[8] = d * e;
te[1] = ac * f + bd;
te[5] = a * e;
te[9] = ad * f - bc;
te[2] = bc * f - ad;
te[6] = b * e;
te[10] = bd * f + ac;
}
// bottom row
te[3] = 0;
te[7] = 0;
te[11] = 0;
// last column
te[12] = 0;
te[13] = 0;
te[14] = 0;
te[15] = 1;
return this;
},
makeRotationFromQuaternion: function()
{
var zero = new Vector3(0, 0, 0);
var one = new Vector3(1, 1, 1);
return function makeRotationFromQuaternion(q) {
return this.compose(zero, q, one);
};
}
(),
lookAt: function()
{
var x = new Vector3();
var y = new Vector3();
var z = new Vector3();
return function lookAt(eye, target, up) {
var te = this.elements;
z.subVectors(eye, target);
if (z.lengthSq() === 0)
{
// eye and target are in the same position
z.z = 1;
}
z.normalize();
x.crossVectors(up, z);
if (x.lengthSq() === 0)
{
// up and z are parallel
if (Math.abs(up.z) === 1)
{
z.x += 0.0001;
}
else
{
z.z += 0.0001;
}
z.normalize();
x.crossVectors(up, z);
}
x.normalize();
y.crossVectors(z, x);
te[0] = x.x; te[4] = y.x; te[8] = z.x;
te[1] = x.y; te[5] = y.y; te[9] = z.y;
te[2] = x.z; te[6] = y.z; te[10] = z.z;
return this;
};
}
(),
multiply: function(m, n )
{
if (n !== undefined)
{
console.warn('THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.');
return this.multiplyMatrices(m, n);
}
return this.multiplyMatrices(this, m);
},
premultiply: function(m )
{
return this.multiplyMatrices(m, this);
},
multiplyMatrices: function(a, b )
{
var ae = a.elements;
var be = b.elements;
var te = this.elements;
var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12];
var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13];
var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14];
var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15];
var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12];
var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13];
var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14];
var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15];
te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
return this;
},
multiplyScalar: function(s )
{
var te = this.elements;
te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s;
te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s;
te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s;
te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s;
return this;
},
applyToBufferAttribute: function()
{
var v1 = new Vector3();
return function applyToBufferAttribute(attribute) {
for (var i = 0, l = attribute.count; i < l; i++)
{
v1.x = attribute.getX(i);
v1.y = attribute.getY(i);
v1.z = attribute.getZ(i);
v1.applyMatrix4(this);
attribute.setXYZ(i, v1.x, v1.y, v1.z);
}
return attribute;
};
}
(),
determinant: function()
{
var te = this.elements;
var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12];
var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13];
var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14];
var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15];
//TODO: make this more efficient
//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
return (
n41 * (
+n14 * n23 * n32
- n13 * n24 * n32
- n14 * n22 * n33
+ n12 * n24 * n33
+ n13 * n22 * n34
- n12 * n23 * n34
) +
n42 * (
+n11 * n23 * n34
- n11 * n24 * n33
+ n14 * n21 * n33
- n13 * n21 * n34
+ n13 * n24 * n31
- n14 * n23 * n31
) +
n43 * (
+n11 * n24 * n32
- n11 * n22 * n34
- n14 * n21 * n32
+ n12 * n21 * n34
+ n14 * n22 * n31
- n12 * n24 * n31
) +
n44 * (
-n13 * n22 * n31
- n11 * n23 * n32
+ n11 * n22 * n33
+ n13 * n21 * n32
- n12 * n21 * n33
+ n12 * n23 * n31
)
);
},
transpose: function()
{
var te = this.elements;
var tmp;
tmp = te[1]; te[1] = te[4]; te[4] = tmp;
tmp = te[2]; te[2] = te[8]; te[8] = tmp;
tmp = te[6]; te[6] = te[9]; te[9] = tmp;
tmp = te[3]; te[3] = te[12]; te[12] = tmp;
tmp = te[7]; te[7] = te[13]; te[13] = tmp;
tmp = te[11]; te[11] = te[14]; te[14] = tmp;
return this;
},
setPosition: function(v )
{
var te = this.elements;
te[12] = v.x;
te[13] = v.y;
te[14] = v.z;
return this;
},
getInverse: function(m, throwOnDegenerate )
{
// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
var te = this.elements,
me = m.elements,
n11 = me[0], n21 = me[1], n31 = me[2], n41 = me[3],
n12 = me[4], n22 = me[5], n32 = me[6], n42 = me[7],
n13 = me[8], n23 = me[9], n33 = me[10], n43 = me[11],
n14 = me[12], n24 = me[13], n34 = me[14], n44 = me[15],
t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
var det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
if (det === 0)
{
var msg = "THREE.Matrix4: .getInverse() can't invert matrix, determinant is 0";
if (throwOnDegenerate === true)
{
throw new Error(msg);
}
else
{
console.warn(msg);
}
return this.identity();
}
var detInv = 1 / det;
te[0] = t11 * detInv;
te[1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * detInv;
te[2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * detInv;
te[3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * detInv;
te[4] = t12 * detInv;
te[5] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * detInv;
te[6] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * detInv;
te[7] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * detInv;
te[8] = t13 * detInv;
te[9] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * detInv;
te[10] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * detInv;
te[11] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * detInv;
te[12] = t14 * detInv;
te[13] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * detInv;
te[14] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * detInv;
te[15] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * detInv;
return this;
},
scale: function(v )
{
var te = this.elements;
var x = v.x, y = v.y, z = v.z;
te[0] *= x; te[4] *= y; te[8] *= z;
te[1] *= x; te[5] *= y; te[9] *= z;
te[2] *= x; te[6] *= y; te[10] *= z;
te[3] *= x; te[7] *= y; te[11] *= z;
return this;
},
getMaxScaleOnAxis: function()
{
var te = this.elements;
var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));
},
makeTranslation: function(x, y, z )
{
this.set(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
);
return this;
},
makeRotationX: function(theta )
{
var c = Math.cos(theta), s = Math.sin(theta);
this.set(
1, 0, 0, 0,
0, c, -s, 0,
0, s, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationY: function(theta )
{
var c = Math.cos(theta), s = Math.sin(theta);
this.set(
c, 0, s, 0,
0, 1, 0, 0,
-s, 0, c, 0,
0, 0, 0, 1
);
return this;
},
makeRotationZ: function(theta )
{
var c = Math.cos(theta), s = Math.sin(theta);
this.set(
c, -s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
},
makeRotationAxis: function(axis, angle )
{
// Based on http://www.gamedev.net/reference/articles/article1199.asp
var c = Math.cos(angle);
var s = Math.sin(angle);
var t = 1 - c;
var x = axis.x, y = axis.y, z = axis.z;
var tx = t * x, ty = t * y;
this.set(
tx * x + c, tx * y - s * z, tx * z + s * y, 0,
tx * y + s * z, ty * y + c, ty * z - s * x, 0,
tx * z - s * y, ty * z + s * x, t * z * z + c, 0,
0, 0, 0, 1
);
return this;
},
makeScale: function(x, y, z )
{
this.set(
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
);
return this;
},
makeShear: function(x, y, z )
{
this.set(
1, y, z, 0,
x, 1, z, 0,
x, y, 1, 0,
0, 0, 0, 1
);
return this;
},
compose: function(position, quaternion, scale )
{
var te = this.elements;
var x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;
var x2 = x + x, y2 = y + y, z2 = z + z;
var xx = x * x2, xy = x * y2, xz = x * z2;
var yy = y * y2, yz = y * z2, zz = z * z2;
var wx = w * x2, wy = w * y2, wz = w * z2;
var sx = scale.x, sy = scale.y, sz = scale.z;
te[0] = (1 - (yy + zz)) * sx;
te[1] = (xy + wz) * sx;
te[2] = (xz - wy) * sx;
te[3] = 0;
te[4] = (xy - wz) * sy;
te[5] = (1 - (xx + zz)) * sy;
te[6] = (yz + wx) * sy;
te[7] = 0;
te[8] = (xz + wy) * sz;
te[9] = (yz - wx) * sz;
te[10] = (1 - (xx + yy)) * sz;
te[11] = 0;
te[12] = position.x;
te[13] = position.y;
te[14] = position.z;
te[15] = 1;
return this;
},
decompose: function()
{
var vector = new Vector3();
var matrix = new Matrix4();
return function decompose(position, quaternion, scale) {
var te = this.elements;
var sx = vector.set(te[0], te[1], te[2]).length();
var sy = vector.set(te[4], te[5], te[6]).length();
var sz = vector.set(te[8], te[9], te[10]).length();
// if determine is negative, we need to invert one scale
var det = this.determinant();
if (det < 0) sx = -sx;
position.x = te[12];
position.y = te[13];
position.z = te[14];
// scale the rotation part
matrix.copy(this);
var invSX = 1 / sx;
var invSY = 1 / sy;
var invSZ = 1 / sz;
matrix.elements[0] *= invSX;
matrix.elements[1] *= invSX;
matrix.elements[2] *= invSX;
matrix.elements[4] *= invSY;
matrix.elements[5] *= invSY;
matrix.elements[6] *= invSY;
matrix.elements[8] *= invSZ;
matrix.elements[9] *= invSZ;
matrix.elements[10] *= invSZ;
quaternion.setFromRotationMatrix(matrix);
scale.x = sx;
scale.y = sy;
scale.z = sz;
return this;
};
}
(),
makePerspective: function(left, right, top, bottom, near, far )
{
if (far === undefined)
{
console.warn('THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.');
}
var te = this.elements;
var x = 2 * near / (right - left);
var y = 2 * near / (top - bottom);
var a = (right + left) / (right - left);
var b = (top + bottom) / (top - bottom);
var c = -(far + near) / (far - near);
var d = -2 * far * near / (far - near);
te[0] = x; te[4] = 0; te[8] = a; te[12] = 0;
te[1] = 0; te[5] = y; te[9] = b; te[13] = 0;
te[2] = 0; te[6] = 0; te[10] = c; te[14] = d;
te[3] = 0; te[7] = 0; te[11] = -1; te[15] = 0;
return this;
},
makeOrthographic: function(left, right, top, bottom, near, far )
{
var te = this.elements;
var w = 1.0 / (right - left);
var h = 1.0 / (top - bottom);
var p = 1.0 / (far - near);
var x = (right + left) * w;
var y = (top + bottom) * h;
var z = (far + near) * p;
te[0] = 2 * w; te[4] = 0; te[8] = 0; te[12] = -x;
te[1] = 0; te[5] = 2 * h; te[9] = 0; te[13] = -y;
te[2] = 0; te[6] = 0; te[10] = -2 * p; te[14] = -z;
te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1;
return this;
},
equals: function(matrix )
{
var te = this.elements;
var me = matrix.elements;
for (var i = 0; i < 16; i++)
{
if (te[i] !== me[i]) return false;
}
return true;
},
fromArray: function(array, offset )
{
if (offset === undefined) offset = 0;
for (var i = 0; i < 16; i++)
{
this.elements[i] = array[i + offset];
}
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
var te = this.elements;
array[offset] = te[0];
array[offset + 1] = te[1];
array[offset + 2] = te[2];
array[offset + 3] = te[3];
array[offset + 4] = te[4];
array[offset + 5] = te[5];
array[offset + 6] = te[6];
array[offset + 7] = te[7];
array[offset + 8] = te[8];
array[offset + 9] = te[9];
array[offset + 10] = te[10];
array[offset + 11] = te[11];
array[offset + 12] = te[12];
array[offset + 13] = te[13];
array[offset + 14] = te[14];
array[offset + 15] = te[15];
return array;
}
}
}

View File

@ -8,6 +8,265 @@ namespace THREE
{
public class Plane
{
function Plane(normal, constant )
{
// normal is assumed to be normalized
this.normal = (normal !== undefined) ? normal : new Vector3(1, 0, 0);
this.constant = (constant !== undefined) ? constant : 0;
}
set: function(normal, constant )
{
this.normal.copy(normal);
this.constant = constant;
return this;
},
setComponents: function(x, y, z, w )
{
this.normal.set(x, y, z);
this.constant = w;
return this;
},
setFromNormalAndCoplanarPoint: function(normal, point )
{
this.normal.copy(normal);
this.constant = -point.dot(this.normal);
return this;
},
setFromCoplanarPoints: function()
{
var v1 = new Vector3();
var v2 = new Vector3();
return function setFromCoplanarPoints(a, b, c) {
var normal = v1.subVectors(c, b).cross(v2.subVectors(a, b)).normalize();
// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
this.setFromNormalAndCoplanarPoint(normal, a);
return this;
};
}
(),
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(plane )
{
this.normal.copy(plane.normal);
this.constant = plane.constant;
return this;
},
normalize: function()
{
// Note: will lead to a divide by zero if the plane is invalid.
var inverseNormalLength = 1.0 / this.normal.length();
this.normal.multiplyScalar(inverseNormalLength);
this.constant *= inverseNormalLength;
return this;
},
negate: function()
{
this.constant *= -1;
this.normal.negate();
return this;
},
distanceToPoint: function(point )
{
return this.normal.dot(point) + this.constant;
},
distanceToSphere: function(sphere )
{
return this.distanceToPoint(sphere.center) - sphere.radius;
},
projectPoint: function(point, target )
{
if (target === undefined)
{
console.warn('THREE.Plane: .projectPoint() target is now required');
target = new Vector3();
}
return target.copy(this.normal).multiplyScalar(-this.distanceToPoint(point)).add(point);
},
intersectLine: function()
{
var v1 = new Vector3();
return function intersectLine(line, target) {
if (target === undefined)
{
console.warn('THREE.Plane: .intersectLine() target is now required');
target = new Vector3();
}
var direction = line.delta(v1);
var denominator = this.normal.dot(direction);
if (denominator === 0)
{
// line is coplanar, return origin
if (this.distanceToPoint(line.start) === 0)
{
return target.copy(line.start);
}
// Unsure if this is the correct method to handle this case.
return undefined;
}
var t = -(line.start.dot(this.normal) + this.constant) / denominator;
if (t < 0 || t > 1)
{
return undefined;
}
return target.copy(direction).multiplyScalar(t).add(line.start);
};
}
(),
intersectsLine: function(line )
{
// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
var startSign = this.distanceToPoint(line.start);
var endSign = this.distanceToPoint(line.end);
return (startSign < 0 && endSign > 0) || (endSign < 0 && startSign > 0);
},
intersectsBox: function(box )
{
return box.intersectsPlane(this);
},
intersectsSphere: function(sphere )
{
return sphere.intersectsPlane(this);
},
coplanarPoint: function(target )
{
if (target === undefined)
{
console.warn('THREE.Plane: .coplanarPoint() target is now required');
target = new Vector3();
}
return target.copy(this.normal).multiplyScalar(-this.constant);
},
applyMatrix4: function()
{
var v1 = new Vector3();
var m1 = new Matrix3();
return function applyMatrix4(matrix, optionalNormalMatrix) {
var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix(matrix);
var referencePoint = this.coplanarPoint(v1).applyMatrix4(matrix);
var normal = this.normal.applyMatrix3(normalMatrix).normalize();
this.constant = -referencePoint.dot(normal);
return this;
};
}
(),
translate: function(offset )
{
this.constant -= offset.dot(this.normal);
return this;
},
equals: function(plane )
{
return plane.normal.equals(this.normal) && (plane.constant === this.constant);
}
}
}

View File

@ -8,6 +8,695 @@ namespace THREE
{
public class Quaternion
{
function Quaternion(x, y, z, w )
{
this._x = x || 0;
this._y = y || 0;
this._z = z || 0;
this._w = (w !== undefined) ? w : 1;
}
slerp: function(qa, qb, qm, t )
{
return qm.copy(qa).slerp(qb, t);
},
slerpFlat: function(dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t )
{
// fuzz-free, array-based Quaternion SLERP operation
var x0 = src0[srcOffset0 + 0],
y0 = src0[srcOffset0 + 1],
z0 = src0[srcOffset0 + 2],
w0 = src0[srcOffset0 + 3],
x1 = src1[srcOffset1 + 0],
y1 = src1[srcOffset1 + 1],
z1 = src1[srcOffset1 + 2],
w1 = src1[srcOffset1 + 3];
if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1)
{
var s = 1 - t,
cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
dir = (cos >= 0 ? 1 : -1),
sqrSin = 1 - cos * cos;
// Skip the Slerp for tiny steps to avoid numeric problems:
if (sqrSin > Number.EPSILON)
{
var sin = Math.sqrt(sqrSin),
len = Math.atan2(sin, cos * dir);
s = Math.sin(s * len) / sin;
t = Math.sin(t * len) / sin;
}
var tDir = t * dir;
x0 = x0 * s + x1 * tDir;
y0 = y0 * s + y1 * tDir;
z0 = z0 * s + z1 * tDir;
w0 = w0 * s + w1 * tDir;
// Normalize in case we just did a lerp:
if (s === 1 - t)
{
var f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
x0 *= f;
y0 *= f;
z0 *= f;
w0 *= f;
}
}
dst[dstOffset] = x0;
dst[dstOffset + 1] = y0;
dst[dstOffset + 2] = z0;
dst[dstOffset + 3] = w0;
}
} );
Object.defineProperties(Quaternion.prototype, {
x: {
get: function()
{
return this._x;
},
set: function(value )
{
this._x = value;
this.onChangeCallback();
}
},
y: {
get: function()
{
return this._y;
},
set: function(value )
{
this._y = value;
this.onChangeCallback();
}
},
z: {
get: function()
{
return this._z;
},
set: function(value )
{
this._z = value;
this.onChangeCallback();
}
},
w: {
get: function()
{
return this._w;
},
set: function(value )
{
this._w = value;
this.onChangeCallback();
}
}
} );
Object.assign(Quaternion.prototype, {
set: function(x, y, z, w )
{
this._x = x;
this._y = y;
this._z = z;
this._w = w;
this.onChangeCallback();
return this;
},
clone: function()
{
return new this.constructor(this._x, this._y, this._z, this._w);
},
copy: function(quaternion )
{
this._x = quaternion.x;
this._y = quaternion.y;
this._z = quaternion.z;
this._w = quaternion.w;
this.onChangeCallback();
return this;
},
setFromEuler: function(euler, update )
{
if (!(euler && euler.isEuler))
{
throw new Error('THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.');
}
var x = euler._x, y = euler._y, z = euler._z, order = euler.order;
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
// content/SpinCalc.m
var cos = Math.cos;
var sin = Math.sin;
var c1 = cos(x / 2);
var c2 = cos(y / 2);
var c3 = cos(z / 2);
var s1 = sin(x / 2);
var s2 = sin(y / 2);
var s3 = sin(z / 2);
if (order === 'XYZ')
{
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
}
else if (order === 'YXZ')
{
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
}
else if (order === 'ZXY')
{
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
}
else if (order === 'ZYX')
{
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
}
else if (order === 'YZX')
{
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
}
else if (order === 'XZY')
{
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
}
if (update !== false) this.onChangeCallback();
return this;
},
setFromAxisAngle: function(axis, angle )
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
// assumes axis is normalized
var halfAngle = angle / 2, s = Math.sin(halfAngle);
this._x = axis.x * s;
this._y = axis.y * s;
this._z = axis.z * s;
this._w = Math.cos(halfAngle);
this.onChangeCallback();
return this;
},
setFromRotationMatrix: function(m )
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var te = m.elements,
m11 = te[0], m12 = te[4], m13 = te[8],
m21 = te[1], m22 = te[5], m23 = te[9],
m31 = te[2], m32 = te[6], m33 = te[10],
trace = m11 + m22 + m33,
s;
if (trace > 0)
{
s = 0.5 / Math.sqrt(trace + 1.0);
this._w = 0.25 / s;
this._x = (m32 - m23) * s;
this._y = (m13 - m31) * s;
this._z = (m21 - m12) * s;
}
else if (m11 > m22 && m11 > m33)
{
s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
this._w = (m32 - m23) / s;
this._x = 0.25 * s;
this._y = (m12 + m21) / s;
this._z = (m13 + m31) / s;
}
else if (m22 > m33)
{
s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
this._w = (m13 - m31) / s;
this._x = (m12 + m21) / s;
this._y = 0.25 * s;
this._z = (m23 + m32) / s;
}
else
{
s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
this._w = (m21 - m12) / s;
this._x = (m13 + m31) / s;
this._y = (m23 + m32) / s;
this._z = 0.25 * s;
}
this.onChangeCallback();
return this;
},
setFromUnitVectors: function()
{
// assumes direction vectors vFrom and vTo are normalized
var v1 = new Vector3();
var r;
var EPS = 0.000001;
return function setFromUnitVectors(vFrom, vTo) {
if (v1 === undefined) v1 = new Vector3();
r = vFrom.dot(vTo) + 1;
if (r < EPS)
{
r = 0;
if (Math.abs(vFrom.x) > Math.abs(vFrom.z))
{
v1.set(-vFrom.y, vFrom.x, 0);
}
else
{
v1.set(0, -vFrom.z, vFrom.y);
}
}
else
{
v1.crossVectors(vFrom, vTo);
}
this._x = v1.x;
this._y = v1.y;
this._z = v1.z;
this._w = r;
return this.normalize();
};
}
(),
angleTo: function(q )
{
return 2 * Math.acos(Math.abs(_Math.clamp(this.dot(q), -1, 1)));
},
rotateTowards: function(q, step )
{
var angle = this.angleTo(q);
if (angle === 0) return this;
var t = Math.min(1, step / angle);
this.slerp(q, t);
return this;
},
inverse: function()
{
// quaternion is assumed to have unit length
return this.conjugate();
},
conjugate: function()
{
this._x *= -1;
this._y *= -1;
this._z *= -1;
this.onChangeCallback();
return this;
},
dot: function(v )
{
return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
},
lengthSq: function()
{
return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
},
length: function()
{
return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
},
normalize: function()
{
var l = this.length();
if (l === 0)
{
this._x = 0;
this._y = 0;
this._z = 0;
this._w = 1;
}
else
{
l = 1 / l;
this._x = this._x * l;
this._y = this._y * l;
this._z = this._z * l;
this._w = this._w * l;
}
this.onChangeCallback();
return this;
},
multiply: function(q, p )
{
if (p !== undefined)
{
console.warn('THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.');
return this.multiplyQuaternions(q, p);
}
return this.multiplyQuaternions(this, q);
},
premultiply: function(q )
{
return this.multiplyQuaternions(q, this);
},
multiplyQuaternions: function(a, b )
{
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;
var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;
this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
this.onChangeCallback();
return this;
},
slerp: function(qb, t )
{
if (t === 0) return this;
if (t === 1) return this.copy(qb);
var x = this._x, y = this._y, z = this._z, w = this._w;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
if (cosHalfTheta < 0)
{
this._w = -qb._w;
this._x = -qb._x;
this._y = -qb._y;
this._z = -qb._z;
cosHalfTheta = -cosHalfTheta;
}
else
{
this.copy(qb);
}
if (cosHalfTheta >= 1.0)
{
this._w = w;
this._x = x;
this._y = y;
this._z = z;
return this;
}
var sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
if (sqrSinHalfTheta <= Number.EPSILON)
{
var s = 1 - t;
this._w = s * w + t * this._w;
this._x = s * x + t * this._x;
this._y = s * y + t * this._y;
this._z = s * z + t * this._z;
return this.normalize();
}
var sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
var halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
this._w = (w * ratioA + this._w * ratioB);
this._x = (x * ratioA + this._x * ratioB);
this._y = (y * ratioA + this._y * ratioB);
this._z = (z * ratioA + this._z * ratioB);
this.onChangeCallback();
return this;
},
equals: function(quaternion )
{
return (quaternion._x === this._x) && (quaternion._y === this._y) && (quaternion._z === this._z) && (quaternion._w === this._w);
},
fromArray: function(array, offset )
{
if (offset === undefined) offset = 0;
this._x = array[offset];
this._y = array[offset + 1];
this._z = array[offset + 2];
this._w = array[offset + 3];
this.onChangeCallback();
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
array[offset] = this._x;
array[offset + 1] = this._y;
array[offset + 2] = this._z;
array[offset + 3] = this._w;
return array;
},
onChange: function(callback )
{
this.onChangeCallback = callback;
return this;
},
onChangeCallback: function() { }
}
}

View File

@ -8,6 +8,610 @@ namespace THREE
{
public class Ray
{
function Ray(origin, direction )
{
this.origin = (origin !== undefined) ? origin : new Vector3();
this.direction = (direction !== undefined) ? direction : new Vector3();
}
set: function(origin, direction )
{
this.origin.copy(origin);
this.direction.copy(direction);
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(ray )
{
this.origin.copy(ray.origin);
this.direction.copy(ray.direction);
return this;
},
at: function(t, target )
{
if (target === undefined)
{
console.warn('THREE.Ray: .at() target is now required');
target = new Vector3();
}
return target.copy(this.direction).multiplyScalar(t).add(this.origin);
},
lookAt: function(v )
{
this.direction.copy(v).sub(this.origin).normalize();
return this;
},
recast: function()
{
var v1 = new Vector3();
return function recast(t) {
this.origin.copy(this.at(t, v1));
return this;
};
}
(),
closestPointToPoint: function(point, target )
{
if (target === undefined)
{
console.warn('THREE.Ray: .closestPointToPoint() target is now required');
target = new Vector3();
}
target.subVectors(point, this.origin);
var directionDistance = target.dot(this.direction);
if (directionDistance < 0)
{
return target.copy(this.origin);
}
return target.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
},
distanceToPoint: function(point )
{
return Math.sqrt(this.distanceSqToPoint(point));
},
distanceSqToPoint: function()
{
var v1 = new Vector3();
return function distanceSqToPoint(point) {
var directionDistance = v1.subVectors(point, this.origin).dot(this.direction);
// point behind the ray
if (directionDistance < 0)
{
return this.origin.distanceToSquared(point);
}
v1.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
return v1.distanceToSquared(point);
};
}
(),
distanceSqToSegment: function()
{
var segCenter = new Vector3();
var segDir = new Vector3();
var diff = new Vector3();
return function distanceSqToSegment(v0, v1, optionalPointOnRay, optionalPointOnSegment) {
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
// It returns the min distance between the ray and the segment
// defined by v0 and v1
// It can also set two optional targets :
// - The closest point on the ray
// - The closest point on the segment
segCenter.copy(v0).add(v1).multiplyScalar(0.5);
segDir.copy(v1).sub(v0).normalize();
diff.copy(this.origin).sub(segCenter);
var segExtent = v0.distanceTo(v1) * 0.5;
var a01 = -this.direction.dot(segDir);
var b0 = diff.dot(this.direction);
var b1 = -diff.dot(segDir);
var c = diff.lengthSq();
var det = Math.abs(1 - a01 * a01);
var s0, s1, sqrDist, extDet;
if (det > 0)
{
// The ray and segment are not parallel.
s0 = a01 * b1 - b0;
s1 = a01 * b0 - b1;
extDet = segExtent * det;
if (s0 >= 0)
{
if (s1 >= -extDet)
{
if (s1 <= extDet)
{
// region 0
// Minimum at interior points of ray and segment.
var invDet = 1 / det;
s0 *= invDet;
s1 *= invDet;
sqrDist = s0 * (s0 + a01 * s1 + 2 * b0) + s1 * (a01 * s0 + s1 + 2 * b1) + c;
}
else
{
// region 1
s1 = segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
}
else
{
// region 5
s1 = -segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
}
else
{
if (s1 <= -extDet)
{
// region 4
s0 = Math.max(0, -(-a01 * segExtent + b0));
s1 = (s0 > 0) ? -segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
else if (s1 <= extDet)
{
// region 3
s0 = 0;
s1 = Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = s1 * (s1 + 2 * b1) + c;
}
else
{
// region 2
s0 = Math.max(0, -(a01 * segExtent + b0));
s1 = (s0 > 0) ? segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
}
}
else
{
// Ray and segment are parallel.
s1 = (a01 > 0) ? -segExtent : segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
if (optionalPointOnRay)
{
optionalPointOnRay.copy(this.direction).multiplyScalar(s0).add(this.origin);
}
if (optionalPointOnSegment)
{
optionalPointOnSegment.copy(segDir).multiplyScalar(s1).add(segCenter);
}
return sqrDist;
};
}
(),
intersectSphere: function()
{
var v1 = new Vector3();
return function intersectSphere(sphere, target) {
v1.subVectors(sphere.center, this.origin);
var tca = v1.dot(this.direction);
var d2 = v1.dot(v1) - tca * tca;
var radius2 = sphere.radius * sphere.radius;
if (d2 > radius2) return null;
var thc = Math.sqrt(radius2 - d2);
// t0 = first intersect point - entrance on front of sphere
var t0 = tca - thc;
// t1 = second intersect point - exit point on back of sphere
var t1 = tca + thc;
// test to see if both t0 and t1 are behind the ray - if so, return null
if (t0 < 0 && t1 < 0) return null;
// test to see if t0 is behind the ray:
// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
// in order to always return an intersect point that is in front of the ray.
if (t0 < 0) return this.at(t1, target);
// else t0 is in front of the ray, so return the first collision point scaled by t0
return this.at(t0, target);
};
}
(),
intersectsSphere: function(sphere )
{
return this.distanceSqToPoint(sphere.center) <= (sphere.radius * sphere.radius);
},
distanceToPlane: function(plane )
{
var denominator = plane.normal.dot(this.direction);
if (denominator === 0)
{
// line is coplanar, return origin
if (plane.distanceToPoint(this.origin) === 0)
{
return 0;
}
// Null is preferable to undefined since undefined means.... it is undefined
return null;
}
var t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
// Return if the ray never intersects the plane
return t >= 0 ? t : null;
},
intersectPlane: function(plane, target )
{
var t = this.distanceToPlane(plane);
if (t === null)
{
return null;
}
return this.at(t, target);
},
intersectsPlane: function(plane )
{
// check if the ray lies on the plane first
var distToPoint = plane.distanceToPoint(this.origin);
if (distToPoint === 0)
{
return true;
}
var denominator = plane.normal.dot(this.direction);
if (denominator * distToPoint < 0)
{
return true;
}
// ray origin is behind the plane (and is pointing behind it)
return false;
},
intersectBox: function(box, target )
{
var tmin, tmax, tymin, tymax, tzmin, tzmax;
var invdirx = 1 / this.direction.x,
invdiry = 1 / this.direction.y,
invdirz = 1 / this.direction.z;
var origin = this.origin;
if (invdirx >= 0)
{
tmin = (box.min.x - origin.x) * invdirx;
tmax = (box.max.x - origin.x) * invdirx;
}
else
{
tmin = (box.max.x - origin.x) * invdirx;
tmax = (box.min.x - origin.x) * invdirx;
}
if (invdiry >= 0)
{
tymin = (box.min.y - origin.y) * invdiry;
tymax = (box.max.y - origin.y) * invdiry;
}
else
{
tymin = (box.max.y - origin.y) * invdiry;
tymax = (box.min.y - origin.y) * invdiry;
}
if ((tmin > tymax) || (tymin > tmax)) return null;
// These lines also handle the case where tmin or tmax is NaN
// (result of 0 * Infinity). x !== x returns true if x is NaN
if (tymin > tmin || tmin !== tmin) tmin = tymin;
if (tymax < tmax || tmax !== tmax) tmax = tymax;
if (invdirz >= 0)
{
tzmin = (box.min.z - origin.z) * invdirz;
tzmax = (box.max.z - origin.z) * invdirz;
}
else
{
tzmin = (box.max.z - origin.z) * invdirz;
tzmax = (box.min.z - origin.z) * invdirz;
}
if ((tmin > tzmax) || (tzmin > tmax)) return null;
if (tzmin > tmin || tmin !== tmin) tmin = tzmin;
if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
//return point closest to the ray (positive side)
if (tmax < 0) return null;
return this.at(tmin >= 0 ? tmin : tmax, target);
},
intersectsBox: (function () {
var v = new Vector3();
return function intersectsBox(box )
{
return this.intersectBox(box, v) !== null;
};
} )(),
intersectTriangle: function()
{
// Compute the offset origin, edges, and normal.
var diff = new Vector3();
var edge1 = new Vector3();
var edge2 = new Vector3();
var normal = new Vector3();
return function intersectTriangle(a, b, c, backfaceCulling, target) {
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
edge1.subVectors(b, a);
edge2.subVectors(c, a);
normal.crossVectors(edge1, edge2);
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
var DdN = this.direction.dot(normal);
var sign;
if (DdN > 0)
{
if (backfaceCulling) return null;
sign = 1;
}
else if (DdN < 0)
{
sign = -1;
DdN = -DdN;
}
else
{
return null;
}
diff.subVectors(this.origin, a);
var DdQxE2 = sign * this.direction.dot(edge2.crossVectors(diff, edge2));
// b1 < 0, no intersection
if (DdQxE2 < 0)
{
return null;
}
var DdE1xQ = sign * this.direction.dot(edge1.cross(diff));
// b2 < 0, no intersection
if (DdE1xQ < 0)
{
return null;
}
// b1+b2 > 1, no intersection
if (DdQxE2 + DdE1xQ > DdN)
{
return null;
}
// Line intersects triangle, check if ray does.
var QdN = -sign * diff.dot(normal);
// t < 0, no intersection
if (QdN < 0)
{
return null;
}
// Ray intersects triangle.
return this.at(QdN / DdN, target);
};
}
(),
applyMatrix4: function(matrix4 )
{
this.origin.applyMatrix4(matrix4);
this.direction.transformDirection(matrix4);
return this;
},
equals: function(ray )
{
return ray.origin.equals(this.origin) && ray.direction.equals(this.direction);
}
}
}

View File

@ -8,6 +8,194 @@ namespace THREE
{
public class Sphere
{
function Sphere(center, radius )
{
this.center = (center !== undefined) ? center : new Vector3();
this.radius = (radius !== undefined) ? radius : 0;
}
set: function(center, radius )
{
this.center.copy(center);
this.radius = radius;
return this;
},
setFromPoints: function()
{
var box = new Box3();
return function setFromPoints(points, optionalCenter) {
var center = this.center;
if (optionalCenter !== undefined)
{
center.copy(optionalCenter);
}
else
{
box.setFromPoints(points).getCenter(center);
}
var maxRadiusSq = 0;
for (var i = 0, il = points.length; i < il; i++)
{
maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i]));
}
this.radius = Math.sqrt(maxRadiusSq);
return this;
};
}
(),
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(sphere )
{
this.center.copy(sphere.center);
this.radius = sphere.radius;
return this;
},
empty: function()
{
return (this.radius <= 0);
},
containsPoint: function(point )
{
return (point.distanceToSquared(this.center) <= (this.radius * this.radius));
},
distanceToPoint: function(point )
{
return (point.distanceTo(this.center) - this.radius);
},
intersectsSphere: function(sphere )
{
var radiusSum = this.radius + sphere.radius;
return sphere.center.distanceToSquared(this.center) <= (radiusSum * radiusSum);
},
intersectsBox: function(box )
{
return box.intersectsSphere(this);
},
intersectsPlane: function(plane )
{
return Math.abs(plane.distanceToPoint(this.center)) <= this.radius;
},
clampPoint: function(point, target )
{
var deltaLengthSq = this.center.distanceToSquared(point);
if (target === undefined)
{
console.warn('THREE.Sphere: .clampPoint() target is now required');
target = new Vector3();
}
target.copy(point);
if (deltaLengthSq > (this.radius * this.radius))
{
target.sub(this.center).normalize();
target.multiplyScalar(this.radius).add(this.center);
}
return target;
},
getBoundingBox: function(target )
{
if (target === undefined)
{
console.warn('THREE.Sphere: .getBoundingBox() target is now required');
target = new Box3();
}
target.set(this.center, this.center);
target.expandByScalar(this.radius);
return target;
},
applyMatrix4: function(matrix )
{
this.center.applyMatrix4(matrix);
this.radius = this.radius * matrix.getMaxScaleOnAxis();
return this;
},
translate: function(offset )
{
this.center.add(offset);
return this;
},
equals: function(sphere )
{
return sphere.center.equals(this.center) && (sphere.radius === this.radius);
}
}
}

View File

@ -8,6 +8,86 @@ namespace THREE
{
public class Spherical
{
function Spherical(radius, phi, theta )
{
this.radius = (radius !== undefined) ? radius : 1.0;
this.phi = (phi !== undefined) ? phi : 0; // polar angle
this.theta = (theta !== undefined) ? theta : 0; // azimuthal angle
return this;
}
set: function(radius, phi, theta )
{
this.radius = radius;
this.phi = phi;
this.theta = theta;
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(other )
{
this.radius = other.radius;
this.phi = other.phi;
this.theta = other.theta;
return this;
},
// restrict phi to be betwee EPS and PI-EPS
makeSafe: function()
{
var EPS = 0.000001;
this.phi = Math.max(EPS, Math.min(Math.PI - EPS, this.phi));
return this;
},
setFromVector3: function(v )
{
return this.setFromCartesianCoords(v.x, v.y, v.z);
},
setFromCartesianCoords: function(x, y, z )
{
this.radius = Math.sqrt(x * x + y * y + z * z);
if (this.radius === 0)
{
this.theta = 0;
this.phi = 0;
}
else
{
this.theta = Math.atan2(x, z);
this.phi = Math.acos(_Math.clamp(y / this.radius, -1, 1));
}
return this;
}
}
}

View File

@ -8,6 +8,378 @@ namespace THREE
{
public class Triangle
{
function Triangle(a, b, c )
{
this.a = (a !== undefined) ? a : new Vector3();
this.b = (b !== undefined) ? b : new Vector3();
this.c = (c !== undefined) ? c : new Vector3();
}
getNormal: function()
{
var v0 = new Vector3();
return function getNormal(a, b, c, target) {
if (target === undefined)
{
console.warn('THREE.Triangle: .getNormal() target is now required');
target = new Vector3();
}
target.subVectors(c, b);
v0.subVectors(a, b);
target.cross(v0);
var targetLengthSq = target.lengthSq();
if (targetLengthSq > 0)
{
return target.multiplyScalar(1 / Math.sqrt(targetLengthSq));
}
return target.set(0, 0, 0);
};
}
(),
// static/instance method to calculate barycentric coordinates
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
getBarycoord: function()
{
var v0 = new Vector3();
var v1 = new Vector3();
var v2 = new Vector3();
return function getBarycoord(point, a, b, c, target) {
v0.subVectors(c, a);
v1.subVectors(b, a);
v2.subVectors(point, a);
var dot00 = v0.dot(v0);
var dot01 = v0.dot(v1);
var dot02 = v0.dot(v2);
var dot11 = v1.dot(v1);
var dot12 = v1.dot(v2);
var denom = (dot00 * dot11 - dot01 * dot01);
if (target === undefined)
{
console.warn('THREE.Triangle: .getBarycoord() target is now required');
target = new Vector3();
}
// collinear or singular triangle
if (denom === 0)
{
// arbitrary location outside of triangle?
// not sure if this is the best idea, maybe should be returning undefined
return target.set(-2, -1, -1);
}
var invDenom = 1 / denom;
var u = (dot11 * dot02 - dot01 * dot12) * invDenom;
var v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// barycentric coordinates must always sum to 1
return target.set(1 - u - v, v, u);
};
}
(),
containsPoint: function()
{
var v1 = new Vector3();
return function containsPoint(point, a, b, c) {
Triangle.getBarycoord(point, a, b, c, v1);
return (v1.x >= 0) && (v1.y >= 0) && ((v1.x + v1.y) <= 1);
};
}
(),
getUV: function()
{
var barycoord = new Vector3();
return function getUV(point, p1, p2, p3, uv1, uv2, uv3, target) {
this.getBarycoord(point, p1, p2, p3, barycoord);
target.set(0, 0);
target.addScaledVector(uv1, barycoord.x);
target.addScaledVector(uv2, barycoord.y);
target.addScaledVector(uv3, barycoord.z);
return target;
};
}
()
} );
Object.assign(Triangle.prototype, {
set: function(a, b, c )
{
this.a.copy(a);
this.b.copy(b);
this.c.copy(c);
return this;
},
setFromPointsAndIndices: function(points, i0, i1, i2 )
{
this.a.copy(points[i0]);
this.b.copy(points[i1]);
this.c.copy(points[i2]);
return this;
},
clone: function()
{
return new this.constructor().copy(this);
},
copy: function(triangle )
{
this.a.copy(triangle.a);
this.b.copy(triangle.b);
this.c.copy(triangle.c);
return this;
},
getArea: function()
{
var v0 = new Vector3();
var v1 = new Vector3();
return function getArea() {
v0.subVectors(this.c, this.b);
v1.subVectors(this.a, this.b);
return v0.cross(v1).length() * 0.5;
};
}
(),
getMidpoint: function(target )
{
if (target === undefined)
{
console.warn('THREE.Triangle: .getMidpoint() target is now required');
target = new Vector3();
}
return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3);
},
getNormal: function(target )
{
return Triangle.getNormal(this.a, this.b, this.c, target);
},
getPlane: function(target )
{
if (target === undefined)
{
console.warn('THREE.Triangle: .getPlane() target is now required');
target = new Vector3();
}
return target.setFromCoplanarPoints(this.a, this.b, this.c);
},
getBarycoord: function(point, target )
{
return Triangle.getBarycoord(point, this.a, this.b, this.c, target);
},
containsPoint: function(point )
{
return Triangle.containsPoint(point, this.a, this.b, this.c);
},
getUV: function(point, uv1, uv2, uv3, result )
{
return Triangle.getUV(point, this.a, this.b, this.c, uv1, uv2, uv3, result);
},
intersectsBox: function(box )
{
return box.intersectsTriangle(this);
},
closestPointToPoint: function()
{
var vab = new Vector3();
var vac = new Vector3();
var vbc = new Vector3();
var vap = new Vector3();
var vbp = new Vector3();
var vcp = new Vector3();
return function closestPointToPoint(p, target) {
if (target === undefined)
{
console.warn('THREE.Triangle: .closestPointToPoint() target is now required');
target = new Vector3();
}
var a = this.a, b = this.b, c = this.c;
var v, w;
// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
// under the accompanying license; see chapter 5.1.5 for detailed explanation.
// basically, we're distinguishing which of the voronoi regions of the triangle
// the point lies in with the minimum amount of redundant computation.
vab.subVectors(b, a);
vac.subVectors(c, a);
vap.subVectors(p, a);
var d1 = vab.dot(vap);
var d2 = vac.dot(vap);
if (d1 <= 0 && d2 <= 0)
{
// vertex region of A; barycentric coords (1, 0, 0)
return target.copy(a);
}
vbp.subVectors(p, b);
var d3 = vab.dot(vbp);
var d4 = vac.dot(vbp);
if (d3 >= 0 && d4 <= d3)
{
// vertex region of B; barycentric coords (0, 1, 0)
return target.copy(b);
}
var vc = d1 * d4 - d3 * d2;
if (vc <= 0 && d1 >= 0 && d3 <= 0)
{
v = d1 / (d1 - d3);
// edge region of AB; barycentric coords (1-v, v, 0)
return target.copy(a).addScaledVector(vab, v);
}
vcp.subVectors(p, c);
var d5 = vab.dot(vcp);
var d6 = vac.dot(vcp);
if (d6 >= 0 && d5 <= d6)
{
// vertex region of C; barycentric coords (0, 0, 1)
return target.copy(c);
}
var vb = d5 * d2 - d1 * d6;
if (vb <= 0 && d2 >= 0 && d6 <= 0)
{
w = d2 / (d2 - d6);
// edge region of AC; barycentric coords (1-w, 0, w)
return target.copy(a).addScaledVector(vac, w);
}
var va = d3 * d6 - d5 * d4;
if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0)
{
vbc.subVectors(c, b);
w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
// edge region of BC; barycentric coords (0, 1-w, w)
return target.copy(b).addScaledVector(vbc, w); // edge region of BC
}
// face region
var denom = 1 / (va + vb + vc);
// u = va * denom
v = vb * denom;
w = vc * denom;
return target.copy(a).addScaledVector(vab, v).addScaledVector(vac, w);
};
}
(),
equals: function(triangle )
{
return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c);
}
}
}

View File

@ -8,6 +8,690 @@ namespace THREE
{
public class Vector4
{
function Vector4(x, y, z, w )
{
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = (w !== undefined) ? w : 1;
}
isVector4: true,
set: function(x, y, z, w )
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
},
setScalar: function(scalar )
{
this.x = scalar;
this.y = scalar;
this.z = scalar;
this.w = scalar;
return this;
},
setX: function(x )
{
this.x = x;
return this;
},
setY: function(y )
{
this.y = y;
return this;
},
setZ: function(z )
{
this.z = z;
return this;
},
setW: function(w )
{
this.w = w;
return this;
},
setComponent: function(index, value )
{
switch (index)
{
case 0: this.x = value; break;
case 1: this.y = value; break;
case 2: this.z = value; break;
case 3: this.w = value; break;
default: throw new Error('index is out of range: ' + index);
}
return this;
},
getComponent: function(index )
{
switch (index)
{
case 0: return this.x;
case 1: return this.y;
case 2: return this.z;
case 3: return this.w;
default: throw new Error('index is out of range: ' + index);
}
},
clone: function()
{
return new this.constructor(this.x, this.y, this.z, this.w);
},
copy: function(v )
{
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = (v.w !== undefined) ? v.w : 1;
return this;
},
add: function(v, w )
{
if (w !== undefined)
{
console.warn('THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
return this.addVectors(v, w);
}
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
},
addScalar: function(s )
{
this.x += s;
this.y += s;
this.z += s;
this.w += s;
return this;
},
addVectors: function(a, b )
{
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
this.w = a.w + b.w;
return this;
},
addScaledVector: function(v, s )
{
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
this.w += v.w * s;
return this;
},
sub: function(v, w )
{
if (w !== undefined)
{
console.warn('THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
return this.subVectors(v, w);
}
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
return this;
},
subScalar: function(s )
{
this.x -= s;
this.y -= s;
this.z -= s;
this.w -= s;
return this;
},
subVectors: function(a, b )
{
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
this.w = a.w - b.w;
return this;
},
multiplyScalar: function(scalar )
{
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
return this;
},
applyMatrix4: function(m )
{
var x = this.x, y = this.y, z = this.z, w = this.w;
var e = m.elements;
this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w;
this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w;
this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w;
this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w;
return this;
},
divideScalar: function(scalar )
{
return this.multiplyScalar(1 / scalar);
},
setAxisAngleFromQuaternion: function(q )
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
// q is assumed to be normalized
this.w = 2 * Math.acos(q.w);
var s = Math.sqrt(1 - q.w * q.w);
if (s < 0.0001)
{
this.x = 1;
this.y = 0;
this.z = 0;
}
else
{
this.x = q.x / s;
this.y = q.y / s;
this.z = q.z / s;
}
return this;
},
setAxisAngleFromRotationMatrix: function(m )
{
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
var angle, x, y, z, // variables for result
epsilon = 0.01, // margin to allow for rounding errors
epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees
te = m.elements,
m11 = te[0], m12 = te[4], m13 = te[8],
m21 = te[1], m22 = te[5], m23 = te[9],
m31 = te[2], m32 = te[6], m33 = te[10];
if ((Math.abs(m12 - m21) < epsilon) &&
(Math.abs(m13 - m31) < epsilon) &&
(Math.abs(m23 - m32) < epsilon))
{
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonal and zero in other terms
if ((Math.abs(m12 + m21) < epsilon2) &&
(Math.abs(m13 + m31) < epsilon2) &&
(Math.abs(m23 + m32) < epsilon2) &&
(Math.abs(m11 + m22 + m33 - 3) < epsilon2))
{
// this singularity is identity matrix so angle = 0
this.set(1, 0, 0, 0);
return this; // zero angle, arbitrary axis
}
// otherwise this singularity is angle = 180
angle = Math.PI;
var xx = (m11 + 1) / 2;
var yy = (m22 + 1) / 2;
var zz = (m33 + 1) / 2;
var xy = (m12 + m21) / 4;
var xz = (m13 + m31) / 4;
var yz = (m23 + m32) / 4;
if ((xx > yy) && (xx > zz))
{
// m11 is the largest diagonal term
if (xx < epsilon)
{
x = 0;
y = 0.707106781;
z = 0.707106781;
}
else
{
x = Math.sqrt(xx);
y = xy / x;
z = xz / x;
}
}
else if (yy > zz)
{
// m22 is the largest diagonal term
if (yy < epsilon)
{
x = 0.707106781;
y = 0;
z = 0.707106781;
}
else
{
y = Math.sqrt(yy);
x = xy / y;
z = yz / y;
}
}
else
{
// m33 is the largest diagonal term so base result on this
if (zz < epsilon)
{
x = 0.707106781;
y = 0.707106781;
z = 0;
}
else
{
z = Math.sqrt(zz);
x = xz / z;
y = yz / z;
}
}
this.set(x, y, z, angle);
return this; // return 180 deg rotation
}
// as we have reached here there are no singularities so we can handle normally
var s = Math.sqrt((m32 - m23) * (m32 - m23) +
(m13 - m31) * (m13 - m31) +
(m21 - m12) * (m21 - m12)); // used to normalize
if (Math.abs(s) < 0.001) s = 1;
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
this.x = (m32 - m23) / s;
this.y = (m13 - m31) / s;
this.z = (m21 - m12) / s;
this.w = Math.acos((m11 + m22 + m33 - 1) / 2);
return this;
},
min: function(v )
{
this.x = Math.min(this.x, v.x);
this.y = Math.min(this.y, v.y);
this.z = Math.min(this.z, v.z);
this.w = Math.min(this.w, v.w);
return this;
},
max: function(v )
{
this.x = Math.max(this.x, v.x);
this.y = Math.max(this.y, v.y);
this.z = Math.max(this.z, v.z);
this.w = Math.max(this.w, v.w);
return this;
},
clamp: function(min, max )
{
// assumes min < max, componentwise
this.x = Math.max(min.x, Math.min(max.x, this.x));
this.y = Math.max(min.y, Math.min(max.y, this.y));
this.z = Math.max(min.z, Math.min(max.z, this.z));
this.w = Math.max(min.w, Math.min(max.w, this.w));
return this;
},
clampScalar: function()
{
var min, max;
return function clampScalar(minVal, maxVal) {
if (min === undefined)
{
min = new Vector4();
max = new Vector4();
}
min.set(minVal, minVal, minVal, minVal);
max.set(maxVal, maxVal, maxVal, maxVal);
return this.clamp(min, max);
};
}
(),
clampLength: function(min, max )
{
var length = this.length();
return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
},
floor: function()
{
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
this.z = Math.floor(this.z);
this.w = Math.floor(this.w);
return this;
},
ceil: function()
{
this.x = Math.ceil(this.x);
this.y = Math.ceil(this.y);
this.z = Math.ceil(this.z);
this.w = Math.ceil(this.w);
return this;
},
round: function()
{
this.x = Math.round(this.x);
this.y = Math.round(this.y);
this.z = Math.round(this.z);
this.w = Math.round(this.w);
return this;
},
roundToZero: function()
{
this.x = (this.x < 0) ? Math.ceil(this.x) : Math.floor(this.x);
this.y = (this.y < 0) ? Math.ceil(this.y) : Math.floor(this.y);
this.z = (this.z < 0) ? Math.ceil(this.z) : Math.floor(this.z);
this.w = (this.w < 0) ? Math.ceil(this.w) : Math.floor(this.w);
return this;
},
negate: function()
{
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
this.w = -this.w;
return this;
},
dot: function(v )
{
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
},
lengthSq: function()
{
return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
},
length: function()
{
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
},
manhattanLength: function()
{
return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w);
},
normalize: function()
{
return this.divideScalar(this.length() || 1);
},
setLength: function(length )
{
return this.normalize().multiplyScalar(length);
},
lerp: function(v, alpha )
{
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
this.z += (v.z - this.z) * alpha;
this.w += (v.w - this.w) * alpha;
return this;
},
lerpVectors: function(v1, v2, alpha )
{
return this.subVectors(v2, v1).multiplyScalar(alpha).add(v1);
},
equals: function(v )
{
return ((v.x === this.x) && (v.y === this.y) && (v.z === this.z) && (v.w === this.w));
},
fromArray: function(array, offset )
{
if (offset === undefined) offset = 0;
this.x = array[offset];
this.y = array[offset + 1];
this.z = array[offset + 2];
this.w = array[offset + 3];
return this;
},
toArray: function(array, offset )
{
if (array === undefined) array = [];
if (offset === undefined) offset = 0;
array[offset] = this.x;
array[offset + 1] = this.y;
array[offset + 2] = this.z;
array[offset + 3] = this.w;
return array;
},
fromBufferAttribute: function(attribute, index, offset )
{
if (offset !== undefined)
{
console.warn('THREE.Vector4: offset has been removed from .fromBufferAttribute().');
}
this.x = attribute.getX(index);
this.y = attribute.getY(index);
this.z = attribute.getZ(index);
this.w = attribute.getW(index);
return this;
}
}
}