three.cjs
three.cjs
* @license
* Copyright 2010-2025 Three.js Authors
* SPDX-License-Identifier: MIT
*/
'use strict';
// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU
names where available.
const NoColorSpace = '';
const SRGBColorSpace = 'srgb';
const LinearSRGBColorSpace = 'srgb-linear';
/**
* https://github.com/mrdoob/eventdispatcher.js/
*/
class EventDispatcher {
if ( index !== - 1 ) {
listenerArray.splice( index, 1 );
dispatchEvent( event ) {
event.target = this;
event.target = null;
const _lut = [ '00', '01', '02', '03', '04', '05', '06', '07', '08', '09', '0a',
'0b', '0c', '0d', '0e', '0f', '10', '11', '12', '13', '14', '15', '16', '17', '18',
'19', '1a', '1b', '1c', '1d', '1e', '1f', '20', '21', '22', '23', '24', '25', '26',
'27', '28', '29', '2a', '2b', '2c', '2d', '2e', '2f', '30', '31', '32', '33', '34',
'35', '36', '37', '38', '39', '3a', '3b', '3c', '3d', '3e', '3f', '40', '41', '42',
'43', '44', '45', '46', '47', '48', '49', '4a', '4b', '4c', '4d', '4e', '4f', '50',
'51', '52', '53', '54', '55', '56', '57', '58', '59', '5a', '5b', '5c', '5d', '5e',
'5f', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '6a', '6b', '6c',
'6d', '6e', '6f', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '7a',
'7b', '7c', '7d', '7e', '7f', '80', '81', '82', '83', '84', '85', '86', '87', '88',
'89', '8a', '8b', '8c', '8d', '8e', '8f', '90', '91', '92', '93', '94', '95', '96',
'97', '98', '99', '9a', '9b', '9c', '9d', '9e', '9f', 'a0', 'a1', 'a2', 'a3', 'a4',
'a5', 'a6', 'a7', 'a8', 'a9', 'aa', 'ab', 'ac', 'ad', 'ae', 'af', 'b0', 'b1', 'b2',
'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'ba', 'bb', 'bc', 'bd', 'be', 'bf', 'c0',
'c1', 'c2', 'c3', 'c4', 'c5', 'c6', 'c7', 'c8', 'c9', 'ca', 'cb', 'cc', 'cd', 'ce',
'cf', 'd0', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'da', 'db', 'dc',
'dd', 'de', 'df', 'e0', 'e1', 'e2', 'e3', 'e4', 'e5', 'e6', 'e7', 'e8', 'e9', 'ea',
'eb', 'ec', 'ed', 'ee', 'ef', 'f0', 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8',
'f9', 'fa', 'fb', 'fc', 'fd', 'fe', 'ff' ];
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-
javascript/21963136#21963136
function generateUUID() {
}
function clamp( value, min, max ) {
return ( ( n % m ) + m ) % m;
return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );
// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/
inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/
function inverseLerp( x, y, value ) {
if ( x !== y ) {
return ( value - x ) / ( y - x );
} else {
return 0;
// https://en.wikipedia.org/wiki/Linear_interpolation
function lerp( x, y, t ) {
return ( 1 - t ) * x + t * y;
// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-
lerp/
function damp( x, y, lambda, dt ) {
// https://www.desmos.com/calculator/vcsjnyz7x4
function pingpong( x, length = 1 ) {
}
// http://en.wikipedia.org/wiki/Smoothstep
function smoothstep( x, min, max ) {
return x * x * ( 3 - 2 * x );
return x * x * x * ( x * ( x * 6 - 15 ) + 10 );
// Mulberry32 generator
t ^= t + Math.imul( t ^ t >>> 7, t | 61 );
const c2 = cos( b / 2 );
const s2 = sin( b / 2 );
switch ( order ) {
case 'XYX':
q.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );
break;
case 'YZY':
q.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );
break;
case 'ZXZ':
q.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );
break;
case 'XZX':
q.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );
break;
case 'YXY':
q.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );
break;
case 'ZYZ':
q.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );
break;
default:
console.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler()
encountered an unknown order: ' + order );
switch ( array.constructor ) {
case Float32Array:
return value;
case Uint32Array:
case Uint16Array:
case Uint8Array:
case Int32Array:
case Int16Array:
return Math.max( value / 32767.0, - 1.0 );
case Int8Array:
default:
switch ( array.constructor ) {
case Float32Array:
return value;
case Uint32Array:
case Uint16Array:
case Uint8Array:
case Int32Array:
case Int16Array:
case Int8Array:
default:
const MathUtils = {
DEG2RAD: DEG2RAD,
RAD2DEG: RAD2DEG,
generateUUID: generateUUID,
clamp: clamp,
euclideanModulo: euclideanModulo,
mapLinear: mapLinear,
inverseLerp: inverseLerp,
lerp: lerp,
damp: damp,
pingpong: pingpong,
smoothstep: smoothstep,
smootherstep: smootherstep,
randInt: randInt,
randFloat: randFloat,
randFloatSpread: randFloatSpread,
seededRandom: seededRandom,
degToRad: degToRad,
radToDeg: radToDeg,
isPowerOfTwo: isPowerOfTwo,
ceilPowerOfTwo: ceilPowerOfTwo,
floorPowerOfTwo: floorPowerOfTwo,
setQuaternionFromProperEuler: setQuaternionFromProperEuler,
normalize: normalize,
denormalize: denormalize
};
class Vector2 {
constructor( x = 0, y = 0 ) {
Vector2.prototype.isVector2 = true;
this.x = x;
this.y = y;
get width() {
return this.x;
this.x = value;
get height() {
return this.y;
this.y = value;
set( x, y ) {
this.x = x;
this.y = y;
return this;
setScalar( scalar ) {
this.x = scalar;
this.y = scalar;
return this;
setX( x ) {
this.x = x;
return this;
setY( y ) {
this.y = y;
return this;
switch ( index ) {
return this;
getComponent( index ) {
switch ( index ) {
clone() {
return new this.constructor( this.x, this.y );
copy( v ) {
this.x = v.x;
this.y = v.y;
return this;
add( v ) {
this.x += v.x;
this.y += v.y;
return this;
addScalar( s ) {
this.x += s;
this.y += s;
return this;
addVectors( a, b ) {
return this;
addScaledVector( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
return this;
sub( v ) {
this.x -= v.x;
this.y -= v.y;
return this;
}
subScalar( s ) {
this.x -= s;
this.y -= s;
return this;
subVectors( a, b ) {
return this;
multiply( v ) {
this.x *= v.x;
this.y *= v.y;
return this;
multiplyScalar( scalar ) {
this.x *= scalar;
this.y *= scalar;
return this;
divide( v ) {
this.x /= v.x;
this.y /= v.y;
return this;
divideScalar( scalar ) {
applyMatrix3( m ) {
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];
return this;
min( v ) {
return this;
max( v ) {
return this;
return this;
return this;
floor() {
return this;
}
ceil() {
return this;
round() {
return this;
roundToZero() {
return this;
negate() {
this.x = - this.x;
this.y = - this.y;
return this;
dot( v ) {
cross( v ) {
lengthSq() {
length() {
manhattanLength() {
normalize() {
angle() {
return angle;
angleTo( v ) {
distanceTo( v ) {
distanceToSquared( v ) {
manhattanDistanceTo( v ) {
setLength( length ) {
return this.normalize().multiplyScalar( length );
lerp( v, alpha ) {
return this;
return this;
equals( v ) {
return this;
return array;
return this;
this.x = x * c - y * s + center.x;
this.y = x * s + y * c + center.y;
return this;
random() {
this.x = Math.random();
this.y = Math.random();
return this;
*[ Symbol.iterator ]() {
yield this.x;
yield this.y;
class Matrix3 {
constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
Matrix3.prototype.isMatrix3 = true;
this.elements = [
1, 0, 0,
0, 1, 0,
0, 0, 1
];
this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );
set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {
const te = this.elements;
return this;
}
identity() {
this.set(
1, 0, 0,
0, 1, 0,
0, 0, 1
);
return this;
copy( m ) {
const te = this.elements;
const me = m.elements;
return this;
xAxis.setFromMatrix3Column( this, 0 );
yAxis.setFromMatrix3Column( this, 1 );
zAxis.setFromMatrix3Column( this, 2 );
return this;
setFromMatrix4( m ) {
const me = m.elements;
this.set(
);
return this;
multiply( m ) {
premultiply( m ) {
multiplyMatrices( a, b ) {
const ae = a.elements;
const be = b.elements;
const te = this.elements;
return this;
multiplyScalar( s ) {
const te = this.elements;
return this;
determinant() {
const te = this.elements;
invert() {
const te = this.elements,
return this;
transpose() {
let tmp;
const 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( matrix4 ) {
transposeIntoArray( r ) {
const 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;
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
);
return this;
//
scale( sx, sy ) {
return this;
rotate( theta ) {
return this;
translate( tx, ty ) {
return this;
// for 2D Transforms
makeTranslation( x, y ) {
if ( x.isVector2 ) {
this.set(
1, 0, x.x,
0, 1, x.y,
0, 0, 1
);
} else {
this.set(
1, 0, x,
0, 1, y,
0, 0, 1
);
return this;
makeRotation( theta ) {
// counterclockwise
this.set(
c, - s, 0,
s, c, 0,
0, 0, 1
);
return this;
makeScale( x, y ) {
this.set(
x, 0, 0,
0, y, 0,
0, 0, 1
);
return this;
}
//
equals( matrix ) {
const te = this.elements;
const me = matrix.elements;
return true;
return this;
const te = this.elements;
return array;
clone() {
}
const _m3 = /*@__PURE__*/ new Matrix3();
return false;
const TYPED_ARRAYS = {
Int8Array: Int8Array,
Uint8Array: Uint8Array,
Uint8ClampedArray: Uint8ClampedArray,
Int16Array: Int16Array,
Uint16Array: Uint16Array,
Int32Array: Int32Array,
Uint32Array: Uint32Array,
Float32Array: Float32Array,
Float64Array: Float64Array
};
function createCanvasElement() {
console.warn( message );
}
function probe() {
case gl.WAIT_FAILED:
reject();
break;
case gl.TIMEOUT_EXPIRED:
setTimeout( probe, interval );
break;
default:
resolve();
} );
const m = projectionMatrix.elements;
const m = projectionMatrix.elements;
const isPerspectiveMatrix = m[ 11 ] === - 1;
m[ 10 ] = - m[ 10 ] - 1;
m[ 14 ] = - m[ 14 ];
} else {
m[ 10 ] = - m[ 10 ];
m[ 14 ] = - m[ 14 ] + 1;
function createColorManagement() {
const ColorManagement = {
enabled: true,
workingColorSpace: LinearSRGBColorSpace,
/**
* Implementations of supported color spaces.
*
* Required:
* - primaries: chromaticity coordinates [ rx ry gx gy bx by ]
* - whitePoint: reference white [ x y ]
* - transfer: transfer function (pre-defined)
* - toXYZ: Matrix3 RGB to XYZ transform
* - fromXYZ: Matrix3 XYZ to RGB transform
* - luminanceCoefficients: RGB luminance coefficients
*
* Optional:
* - outputColorSpaceConfig: { drawingBufferColorSpace: ColorSpace }
* - workingColorSpaceConfig: { unpackColorSpace: ColorSpace }
*
* Reference:
* - https://www.russellcottrell.com/photo/matrixCalculator.htm
*/
spaces: {},
return color;
return color;
},
},
},
},
},
},
},
// Internal APIs
return targetMatrix
.copy( this.spaces[ sourceColorSpace ].toXYZ )
.multiply( this.spaces[ targetColorSpace ].fromXYZ );
},
return
this.spaces[ colorSpace ].outputColorSpaceConfig.drawingBufferColorSpace;
},
return
this.spaces[ colorSpace ].workingColorSpaceConfig.unpackColorSpace;
};
/******************************************************************************
* sRGB definitions
*/
ColorManagement.define( {
[ LinearSRGBColorSpace ]: {
primaries: REC709_PRIMARIES,
whitePoint: D65,
transfer: LinearTransfer,
toXYZ: LINEAR_REC709_TO_XYZ,
fromXYZ: XYZ_TO_LINEAR_REC709,
luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
workingColorSpaceConfig: { unpackColorSpace: SRGBColorSpace },
outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace
}
},
[ SRGBColorSpace ]: {
primaries: REC709_PRIMARIES,
whitePoint: D65,
transfer: SRGBTransfer,
toXYZ: LINEAR_REC709_TO_XYZ,
fromXYZ: XYZ_TO_LINEAR_REC709,
luminanceCoefficients: REC709_LUMINANCE_COEFFICIENTS,
outputColorSpaceConfig: { drawingBufferColorSpace: SRGBColorSpace
}
},
} );
return ColorManagement;
function SRGBToLinear( c ) {
function LinearToSRGB( c ) {
let _canvas;
class ImageUtils {
if ( /^data:/i.test( image.src ) ) {
return image.src;
return image.src;
let canvas;
canvas = image;
} else {
_canvas.width = image.width;
_canvas.height = image.height;
context.putImageData( image, 0, 0 );
} else {
canvas = _canvas;
} else {
canvas.width = image.width;
canvas.height = image.height;
context.putImageData( imageData, 0, 0 );
return canvas;
} else if ( image.data ) {
} else {
// assuming float
return {
data: data,
width: image.width,
height: image.height
};
} else {
let _sourceId = 0;
class Source {
this.uuid = generateUUID();
this.data = data;
this.dataReady = true;
this.version = 0;
toJSON( meta ) {
const output = {
uuid: this.uuid,
url: ''
};
let url;
if ( Array.isArray( data ) ) {
// cube texture
url = [];
if ( data[ i ].isDataTexture ) {
} else {
}
}
} else {
// texture
output.url = url;
if ( ! isRootObject ) {
return output;
// default images
} else {
if ( image.data ) {
// images of DataTexture
return {
data: Array.from( image.data ),
width: image.width,
height: image.height,
type: image.data.constructor.name
};
} else {
}
}
let _textureId = 0;
super();
this.isTexture = true;
this.uuid = generateUUID();
this.name = '';
this.mapping = mapping;
this.channel = 0;
this.wrapS = wrapS;
this.wrapT = wrapT;
this.magFilter = magFilter;
this.minFilter = minFilter;
this.anisotropy = anisotropy;
this.format = format;
this.internalFormat = null;
this.type = type;
this.matrixAutoUpdate = true;
this.matrix = new Matrix3();
this.generateMipmaps = true;
this.premultiplyAlpha = false;
this.flipY = true;
this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see
http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
this.colorSpace = colorSpace;
this.userData = {};
this.version = 0;
this.onUpdate = null;
get image() {
return this.source.data;
this.source.data = value;
updateMatrix() {
clone() {
copy( source ) {
this.name = source.name;
this.source = source.source;
this.mipmaps = source.mipmaps.slice( 0 );
this.mapping = source.mapping;
this.channel = source.channel;
this.wrapS = source.wrapS;
this.wrapT = source.wrapT;
this.magFilter = source.magFilter;
this.minFilter = source.minFilter;
this.anisotropy = source.anisotropy;
this.format = source.format;
this.internalFormat = source.internalFormat;
this.type = source.type;
this.offset.copy( source.offset );
this.repeat.copy( source.repeat );
this.center.copy( source.center );
this.rotation = source.rotation;
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrix.copy( source.matrix );
this.generateMipmaps = source.generateMipmaps;
this.premultiplyAlpha = source.premultiplyAlpha;
this.flipY = source.flipY;
this.unpackAlignment = source.unpackAlignment;
this.colorSpace = source.colorSpace;
this.renderTarget = source.renderTarget;
this.isRenderTargetTexture = source.isRenderTargetTexture;
this.needsUpdate = true;
return this;
toJSON( meta ) {
const output = {
metadata: {
version: 4.6,
type: 'Texture',
generator: 'Texture.toJSON'
},
uuid: this.uuid,
name: this.name,
mapping: this.mapping,
channel: this.channel,
minFilter: this.minFilter,
magFilter: this.magFilter,
anisotropy: this.anisotropy,
flipY: this.flipY,
generateMipmaps: this.generateMipmaps,
premultiplyAlpha: this.premultiplyAlpha,
unpackAlignment: this.unpackAlignment
};
if ( ! isRootObject ) {
return output;
dispose() {
transformUv( uv ) {
uv.applyMatrix3( this.matrix );
switch ( this.wrapS ) {
case RepeatWrapping:
case ClampToEdgeWrapping:
case MirroredRepeatWrapping:
} else {
break;
switch ( this.wrapT ) {
case RepeatWrapping:
case ClampToEdgeWrapping:
case MirroredRepeatWrapping:
} else {
break;
if ( this.flipY ) {
uv.y = 1 - uv.y;
return uv;
this.version ++;
this.source.needsUpdate = true;
this.pmremVersion ++;
Texture.DEFAULT_IMAGE = null;
Texture.DEFAULT_MAPPING = UVMapping;
Texture.DEFAULT_ANISOTROPY = 1;
class Vector4 {
constructor( x = 0, y = 0, z = 0, w = 1 ) {
Vector4.prototype.isVector4 = true;
this.x = x;
this.y = y;
this.z = z;
this.w = w;
get width() {
return this.z;
this.z = value;
get height() {
return this.w;
this.w = value;
}
set( x, y, z, w ) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
setScalar( scalar ) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
this.w = scalar;
return this;
setX( x ) {
this.x = x;
return this;
setY( y ) {
this.y = y;
return this;
setZ( z ) {
this.z = z;
return this;
setW( w ) {
this.w = w;
return this;
return this;
getComponent( index ) {
switch ( index ) {
clone() {
copy( v ) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = ( v.w !== undefined ) ? v.w : 1;
return this;
add( v ) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
addScalar( s ) {
this.x += s;
this.y += s;
this.z += s;
this.w += s;
return this;
addVectors( a, b ) {
return this;
addScaledVector( 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( v ) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
return this;
subScalar( s ) {
this.x -= s;
this.y -= s;
this.z -= s;
this.w -= s;
return this;
subVectors( a, b ) {
multiply( v ) {
this.x *= v.x;
this.y *= v.y;
this.z *= v.z;
this.w *= v.w;
return this;
multiplyScalar( scalar ) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
return this;
applyMatrix4( m ) {
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;
divide( v ) {
this.x /= v.x;
this.y /= v.y;
this.z /= v.z;
this.w /= v.w;
return this;
divideScalar( scalar ) {
setAxisAngleFromQuaternion( q ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/
quaternionToAngle/index.htm
// q is assumed to be normalized
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( m ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/
matrixToAngle/index.htm
te = m.elements,
// singularity found
// first check for identity matrix which must have +1 for all
terms
// in leading diagonal and zero in other terms
this.set( 1, 0, 0, 0 );
angle = Math.PI;
const xx = ( m11 + 1 ) / 2;
const yy = ( m22 + 1 ) / 2;
const zz = ( m33 + 1 ) / 2;
const xy = ( m12 + m21 ) / 4;
const xz = ( m13 + m31 ) / 4;
const yz = ( m23 + m32 ) / 4;
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 ) {
if ( yy < epsilon ) {
x = 0.707106781;
y = 0;
z = 0.707106781;
} else {
y = Math.sqrt( yy );
x = xy / y;
z = yz / y;
} else {
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;
setFromMatrixPosition( m ) {
const e = m.elements;
this.x = e[ 12 ];
this.y = e[ 13 ];
this.z = e[ 14 ];
this.w = e[ 15 ];
return this;
min( 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( v ) {
return this;
return this;
return this;
floor() {
ceil() {
return this;
round() {
return this;
roundToZero() {
return this;
negate() {
this.x = - this.x;
this.y = - this.y;
this.z = - this.z;
this.w = - this.w;
return this;
dot( v ) {
lengthSq() {
length() {
manhattanLength() {
normalize() {
setLength( length ) {
lerp( v, alpha ) {
return this;
return this;
equals( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z )
&& ( v.w === this.w ) );
return this;
return array;
return this;
random() {
this.x = Math.random();
this.y = Math.random();
this.z = Math.random();
this.w = Math.random();
return this;
*[ Symbol.iterator ]() {
yield this.x;
yield this.y;
yield this.z;
yield this.w;
/*
In options, we can specify:
* Texture parameters for an auto-generated target texture
* depthBuffer/stencilBuffer: Booleans to indicate if we should generate these
buffers
*/
class RenderTarget extends EventDispatcher {
super();
this.isRenderTarget = true;
this.width = width;
this.height = height;
this.depth = 1;
options = Object.assign( {
generateMipmaps: false,
internalFormat: null,
minFilter: LinearFilter,
depthBuffer: true,
stencilBuffer: false,
resolveDepthBuffer: true,
resolveStencilBuffer: true,
depthTexture: null,
samples: 0,
count: 1
}, options );
texture.flipY = false;
texture.generateMipmaps = options.generateMipmaps;
texture.internalFormat = options.internalFormat;
this.textures = [];
this.textures[ i ] = texture.clone();
this.textures[ i ].isRenderTargetTexture = true;
this.textures[ i ].renderTarget = this;
this.depthBuffer = options.depthBuffer;
this.stencilBuffer = options.stencilBuffer;
this.resolveDepthBuffer = options.resolveDepthBuffer;
this.resolveStencilBuffer = options.resolveStencilBuffer;
this._depthTexture = null;
this.depthTexture = options.depthTexture;
this.samples = options.samples;
get texture() {
return this.textures[ 0 ];
this.textures[ 0 ] = value;
this._depthTexture = current;
get depthTexture() {
return this._depthTexture;
this.width = width;
this.height = height;
this.depth = depth;
this.dispose();
}
clone() {
copy( source ) {
this.width = source.width;
this.height = source.height;
this.depth = source.depth;
this.scissor.copy( source.scissor );
this.scissorTest = source.scissorTest;
this.viewport.copy( source.viewport );
this.textures.length = 0;
this.depthBuffer = source.depthBuffer;
this.stencilBuffer = source.stencilBuffer;
this.resolveDepthBuffer = source.resolveDepthBuffer;
this.resolveStencilBuffer = source.resolveStencilBuffer;
this.samples = source.samples;
return this;
dispose() {
this.isWebGLRenderTarget = true;
super( null );
this.isDataArrayTexture = true;
this.magFilter = NearestFilter;
this.minFilter = NearestFilter;
this.wrapR = ClampToEdgeWrapping;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
addLayerUpdate( layerIndex ) {
this.layerUpdates.add( layerIndex );
clearLayerUpdates() {
this.layerUpdates.clear();
this.isWebGLArrayRenderTarget = true;
this.depth = depth;
this.texture.isRenderTargetTexture = true;
}
super( null );
this.isData3DTexture = true;
this.magFilter = NearestFilter;
this.minFilter = NearestFilter;
this.wrapR = ClampToEdgeWrapping;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
this.isWebGL3DRenderTarget = true;
this.depth = depth;
this.texture.isRenderTargetTexture = true;
class Quaternion {
constructor( x = 0, y = 0, z = 0, w = 1 ) {
this.isQuaternion = true;
this._x = x;
this._y = y;
this._z = z;
this._w = w;
if ( t === 0 ) {
if ( t === 1 ) {
let s = 1 - t;
const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
dir = ( cos >= 0 ? 1 : - 1 ),
sqrSin = 1 - cos * cos;
x0 = x0 * s + x1 * tDir;
y0 = y0 * s + y1 * tDir;
z0 = z0 * s + z1 * tDir;
w0 = w0 * s + w1 * tDir;
const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 *
w0 );
x0 *= f;
y0 *= f;
z0 *= f;
w0 *= f;
return dst;
get x() {
return this._x;
}
set x( value ) {
this._x = value;
this._onChangeCallback();
get y() {
return this._y;
set y( value ) {
this._y = value;
this._onChangeCallback();
get z() {
return this._z;
set z( value ) {
this._z = value;
this._onChangeCallback();
get w() {
return this._w;
set w( value ) {
this._w = value;
this._onChangeCallback();
set( x, y, z, w ) {
this._x = x;
this._y = y;
this._z = z;
this._w = w;
this._onChangeCallback();
return this;
}
clone() {
copy( quaternion ) {
this._x = quaternion.x;
this._y = quaternion.y;
this._z = quaternion.z;
this._w = quaternion.w;
this._onChangeCallback();
return this;
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-
and-euler-vectors/
// content/SpinCalc.m
const c1 = cos( x / 2 );
const c2 = cos( y / 2 );
const c3 = cos( z / 2 );
const s1 = sin( x / 2 );
const s2 = sin( y / 2 );
const s3 = sin( z / 2 );
switch ( order ) {
case '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;
break;
case '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;
break;
case '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;
break;
case '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;
break;
case '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;
break;
case '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;
break;
default:
console.warn( 'THREE.Quaternion: .setFromEuler()
encountered an unknown order: ' + order );
return this;
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/
angleToQuaternion/index.htm
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( m ) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/
matrixToQuaternion/index.htm
const te = m.elements,
if ( trace > 0 ) {
this._w = 0.25 / s;
this._x = ( m32 - m23 ) * s;
this._y = ( m13 - m31 ) * s;
this._z = ( m21 - m12 ) * s;
} else {
this._onChangeCallback();
return this;
if ( r < Number.EPSILON ) {
r = 0;
this._x = - vFrom.y;
this._y = vFrom.x;
this._z = 0;
this._w = r;
} else {
this._x = 0;
this._y = - vFrom.z;
this._z = vFrom.y;
this._w = r;
} else {
return this.normalize();
angleTo( q ) {
rotateTowards( q, step ) {
this.slerp( q, t );
return this;
}
identity() {
return this.set( 0, 0, 0, 1 );
invert() {
return this.conjugate();
conjugate() {
this._x *= - 1;
this._y *= - 1;
this._z *= - 1;
this._onChangeCallback();
return this;
dot( v ) {
lengthSq() {
length() {
normalize() {
let 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( q ) {
premultiply( q ) {
multiplyQuaternions( a, b ) {
// from
http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/
index.htm
this._onChangeCallback();
return this;
slerp( qb, t ) {
//
http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
let 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 );
this._w = w;
this._x = x;
this._y = y;
this._z = z;
return this;
const 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;
this._onChangeCallback();
return this;
}
random() {
// Ken Shoemake
// Uniform random rotations
// D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press,
New York, 1992.
const x0 = Math.random();
const r1 = Math.sqrt( 1 - x0 );
const r2 = Math.sqrt( x0 );
return this.set(
r1 * Math.sin( theta1 ),
r1 * Math.cos( theta1 ),
r2 * Math.sin( theta2 ),
r2 * Math.cos( theta2 ),
);
equals( quaternion ) {
this._onChangeCallback();
return this;
this._onChangeCallback();
return this;
toJSON() {
return this.toArray();
_onChange( callback ) {
this._onChangeCallback = callback;
return this;
_onChangeCallback() {}
*[ Symbol.iterator ]() {
yield this._x;
yield this._y;
yield this._z;
yield this._w;
class Vector3 {
constructor( x = 0, y = 0, z = 0 ) {
Vector3.prototype.isVector3 = true;
this.x = x;
this.y = y;
this.z = z;
set( x, y, z ) {
if ( z === undefined ) z = this.z; // sprite.scale.set(x,y)
this.x = x;
this.y = y;
this.z = z;
return this;
setScalar( scalar ) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
return this;
setX( x ) {
this.x = x;
return this;
setY( y ) {
this.y = y;
return this;
setZ( z ) {
this.z = z;
return this;
switch ( index ) {
return this;
}
getComponent( index ) {
switch ( index ) {
clone() {
copy( v ) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
add( v ) {
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
addScalar( s ) {
this.x += s;
this.y += s;
this.z += s;
return this;
addVectors( a, b ) {
return this;
}
addScaledVector( v, s ) {
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
return this;
sub( v ) {
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
return this;
subScalar( s ) {
this.x -= s;
this.y -= s;
this.z -= s;
return this;
subVectors( a, b ) {
return this;
multiply( v ) {
this.x *= v.x;
this.y *= v.y;
this.z *= v.z;
return this;
multiplyScalar( scalar ) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
return this;
}
multiplyVectors( a, b ) {
return this;
applyEuler( euler ) {
applyMatrix3( m ) {
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
return this;
applyNormalMatrix( m ) {
applyMatrix4( m ) {
const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );
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;
return this;
applyQuaternion( q ) {
// quaternion q is assumed to have unit length
// t = 2 * cross( q.xyz, v );
const tx = 2 * ( qy * vz - qz * vy );
const ty = 2 * ( qz * vx - qx * vz );
const tz = 2 * ( qx * vy - qy * vx );
return this;
project( camera ) {
return
this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatri
x );
unproject( camera ) {
return
this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorl
d );
transformDirection( m ) {
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
return this.normalize();
divide( v ) {
this.x /= v.x;
this.y /= v.y;
this.z /= v.z;
return this;
}
divideScalar( scalar ) {
min( v ) {
return this;
max( v ) {
return this;
return this;
return this;
}
floor() {
return this;
ceil() {
return this;
round() {
return this;
roundToZero() {
return this;
negate() {
this.x = - this.x;
this.y = - this.y;
this.z = - this.z;
return this;
dot( v ) {
// TODO lengthSquared?
lengthSq() {
length() {
manhattanLength() {
normalize() {
setLength( length ) {
lerp( v, alpha ) {
return this;
return this;
cross( v ) {
crossVectors( a, b ) {
const ax = a.x, ay = a.y, az = a.z;
const bx = b.x, by = b.y, bz = b.z;
this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;
return this;
projectOnVector( v ) {
projectOnPlane( planeNormal ) {
reflect( normal ) {
angleTo( v ) {
distanceTo( v ) {
distanceToSquared( v ) {
return dx * dx + dy * dy + dz * dz;
manhattanDistanceTo( v ) {
setFromSpherical( s ) {
return this;
setFromCylindrical( c ) {
return this;
setFromMatrixPosition( m ) {
const e = m.elements;
this.x = e[ 12 ];
this.y = e[ 13 ];
this.z = e[ 14 ];
return this;
setFromMatrixScale( m ) {
this.x = sx;
this.y = sy;
this.z = sz;
return this;
setFromMatrixColumn( m, index ) {
setFromMatrix3Column( m, index ) {
setFromEuler( e ) {
this.x = e._x;
this.y = e._y;
this.z = e._z;
return this;
setFromColor( c ) {
this.x = c.r;
this.y = c.g;
this.z = c.b;
return this;
equals( v ) {
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z )
);
return this;
return array;
return this;
random() {
this.x = Math.random();
this.y = Math.random();
this.z = Math.random();
return this;
randomDirection() {
// https://mathworld.wolfram.com/SpherePointPicking.html
return this;
*[ Symbol.iterator ]() {
yield this.x;
yield this.y;
yield this.z;
}
class Box3 {
this.isBox3 = true;
this.min = min;
this.max = max;
this.min.copy( min );
this.max.copy( max );
return this;
setFromArray( array ) {
this.makeEmpty();
return this;
setFromBufferAttribute( attribute ) {
this.makeEmpty();
return this;
setFromPoints( points ) {
this.makeEmpty();
this.expandByPoint( points[ i ] );
return this;
return this;
this.makeEmpty();
clone() {
copy( box ) {
this.min.copy( box.min );
this.max.copy( box.max );
return this;
makeEmpty() {
return this;
isEmpty() {
// this is a more robust check for empty than ( volume <= 0 ) because
volume can get positive with two negative axes
getCenter( target ) {
getSize( target ) {
expandByPoint( point ) {
this.min.min( point );
this.max.max( point );
return this;
expandByVector( vector ) {
this.min.sub( vector );
this.max.add( vector );
return this;
expandByScalar( scalar ) {
this.min.addScalar( - scalar );
this.max.addScalar( scalar );
return this;
object.getVertexPosition( i, _vector$b );
} else {
_vector$b.fromBufferAttribute( positionAttribute, i );
_vector$b.applyMatrix4( object.matrixWorld );
this.expandByPoint( _vector$b );
} else {
object.computeBoundingBox();
_box$4.copy( object.boundingBox );
} else {
geometry.computeBoundingBox();
_box$4.copy( geometry.boundingBox );
}
_box$4.applyMatrix4( object.matrixWorld );
this.union( _box$4 );
return this;
containsPoint( point ) {
containsBox( box ) {
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( box ) {
intersectsSphere( sphere ) {
// Find the point on the AABB closest to the sphere center.
this.clampPoint( sphere.center, _vector$b );
// If that point is inside the sphere, the AABB and sphere intersect.
return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius
* sphere.radius );
intersectsPlane( plane ) {
if ( plane.normal.x > 0 ) {
} else {
if ( plane.normal.y > 0 ) {
} else {
if ( plane.normal.z > 0 ) {
} else {
}
intersectsTriangle( triangle ) {
if ( this.isEmpty() ) {
return false;
return false;
return false;
distanceToPoint( point ) {
getBoundingSphere( target ) {
if ( this.isEmpty() ) {
target.makeEmpty();
} else {
this.getCenter( target.center );
return target;
intersect( box ) {
this.min.max( box.min );
this.max.min( box.max );
return this;
union( box ) {
this.min.min( box.min );
this.max.max( box.max );
return this;
applyMatrix4( matrix ) {
this.setFromPoints( _points );
return this;
translate( offset ) {
this.min.add( offset );
this.max.add( offset );
return this;
equals( box ) {
const _points = [
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3(),
/*@__PURE__*/ new Vector3()
];
_testAxis.fromArray( axes, i );
// project the aabb onto the separating axis
const 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 separating axis
const p0 = v0.dot( _testAxis );
const p1 = v1.dot( _testAxis );
const 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 )
{
return true;
class Sphere {
this.isSphere = true;
this.center = center;
this.radius = radius;
this.center.copy( center );
this.radius = radius;
return this;
center.copy( optionalCenter );
} else {
let maxRadiusSq = 0;
return this;
copy( sphere ) {
this.center.copy( sphere.center );
this.radius = sphere.radius;
return this;
isEmpty() {
makeEmpty() {
this.center.set( 0, 0, 0 );
this.radius = - 1;
return this;
}
containsPoint( point ) {
distanceToPoint( point ) {
intersectsSphere( sphere ) {
intersectsBox( box ) {
intersectsPlane( plane ) {
target.copy( point );
return target;
getBoundingBox( target ) {
if ( this.isEmpty() ) {
return target;
applyMatrix4( matrix ) {
this.center.applyMatrix4( matrix );
this.radius = this.radius * matrix.getMaxScaleOnAxis();
return this;
translate( offset ) {
this.center.add( offset );
return this;
expandByPoint( point ) {
if ( this.isEmpty() ) {
this.center.copy( point );
this.radius = 0;
return this;
this.radius += delta;
return this;
}
union( sphere ) {
if ( sphere.isEmpty() ) {
return this;
if ( this.isEmpty() ) {
this.copy( sphere );
return this;
} else {
_v2$3.subVectors( sphere.center,
this.center ).setLength( sphere.radius );
return this;
equals( sphere ) {
clone() {
this.origin = origin;
this.direction = direction;
this.origin.copy( origin );
this.direction.copy( direction );
return this;
copy( ray ) {
this.origin.copy( ray.origin );
this.direction.copy( ray.direction );
return this;
at( t, target ) {
lookAt( v ) {
return this;
recast( t ) {
return this;
if ( directionDistance < 0 ) {
distanceToPoint( point ) {
distanceSqToPoint( point ) {
if ( directionDistance < 0 ) {
// from
https://github.com/pmjoniak/GeometricTools/blob/master/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
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.
} 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
// region 3
s0 = 0;
s1 = Math.min( Math.max( - segExtent, - b1 ),
segExtent );
sqrDist = s1 * ( s1 + 2 * b1 ) + c;
} else {
// region 2
} else {
if ( optionalPointOnRay ) {
if ( optionalPointOnSegment ) {
return sqrDist;
intersectsSphere( sphere ) {
distanceToPlane( plane ) {
if ( denominator === 0 ) {
return 0;
return null;
if ( t === null ) {
return null;
intersectsPlane( plane ) {
if ( distToPoint === 0 ) {
return true;
return true;
return false;
if ( invdirx >= 0 ) {
} else {
if ( invdiry >= 0 ) {
tymin = ( box.min.y - origin.y ) * invdiry;
tymax = ( box.max.y - origin.y ) * invdiry;
} else {
if ( invdirz >= 0 ) {
} else {
intersectsBox( box ) {
// from
https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/
Mathematics/GteIntrRay3Triangle3.h
_edge1.subVectors( b, a );
_edge2.subVectors( c, a );
_normal$1.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)
let DdN = this.direction.dot( _normal$1 );
let sign;
if ( DdN > 0 ) {
sign = - 1;
DdN = - DdN;
} else {
return null;
_diff.subVectors( this.origin, a );
const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff,
_edge2 ) );
// b1 < 0, no intersection
if ( DdQxE2 < 0 ) {
return null;
// b2 < 0, no intersection
if ( DdE1xQ < 0 ) {
return null;
return null;
// t < 0, no intersection
if ( QdN < 0 ) {
return null;
}
applyMatrix4( matrix4 ) {
this.origin.applyMatrix4( matrix4 );
this.direction.transformDirection( matrix4 );
return this;
equals( ray ) {
clone() {
class Matrix4 {
constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41,
n42, n43, n44 ) {
Matrix4.prototype.isMatrix4 = true;
this.elements = [
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
];
this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33,
n34, n41, n42, n43, n44 );
set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42,
n43, n44 ) {
const te = this.elements;
return this;
identity() {
this.set(
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
clone() {
copy( m ) {
const te = this.elements;
const me = m.elements;
return this;
copyPosition( m ) {
te[ 12 ] = me[ 12 ];
te[ 13 ] = me[ 13 ];
te[ 14 ] = me[ 14 ];
return this;
setFromMatrix3( m ) {
const me = m.elements;
this.set(
);
return this;
xAxis.setFromMatrixColumn( this, 0 );
yAxis.setFromMatrixColumn( this, 1 );
zAxis.setFromMatrixColumn( this, 2 );
return this;
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( m ) {
const te = this.elements;
const me = m.elements;
te[ 12 ] = 0;
te[ 13 ] = 0;
te[ 14 ] = 0;
te[ 15 ] = 1;
return this;
makeRotationFromEuler( euler ) {
const te = this.elements;
const 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;
const 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;
const 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;
const 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;
const 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;
const 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( q ) {
const te = this.elements;
if ( _z.lengthSq() === 0 ) {
_z.z = 1;
_z.normalize();
_x.crossVectors( up, _z );
if ( _x.lengthSq() === 0 ) {
_z.x += 0.0001;
} else {
_z.z += 0.0001;
}
_z.normalize();
_x.crossVectors( up, _z );
_x.normalize();
_y.crossVectors( _z, _x );
return this;
multiply( m ) {
premultiply( m ) {
multiplyMatrices( a, b ) {
const ae = a.elements;
const be = b.elements;
const te = this.elements;
return this;
multiplyScalar( s ) {
const te = this.elements;
return this;
determinant() {
const te = this.elements;
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() {
const te = this.elements;
let tmp;
return this;
setPosition( x, y, z ) {
const te = this.elements;
if ( x.isVector3 ) {
te[ 12 ] = x.x;
te[ 13 ] = x.y;
te[ 14 ] = x.z;
} else {
te[ 12 ] = x;
te[ 13 ] = y;
te[ 14 ] = z;
return this;
invert() {
// based on
http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/
index.htm
const te = this.elements,
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;
const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
return this;
}
scale( v ) {
const te = this.elements;
const x = v.x, y = v.y, z = v.z;
return this;
getMaxScaleOnAxis() {
const te = this.elements;
makeTranslation( x, y, z ) {
if ( x.isVector3 ) {
this.set(
1, 0, 0, x.x,
0, 1, 0, x.y,
0, 0, 1, x.z,
0, 0, 0, 1
);
} else {
this.set(
1, 0, 0, x,
0, 1, 0, y,
0, 0, 1, z,
0, 0, 0, 1
);
return this;
}
makeRotationX( theta ) {
this.set(
1, 0, 0, 0,
0, c, - s, 0,
0, s, c, 0,
0, 0, 0, 1
);
return this;
makeRotationY( theta ) {
this.set(
c, 0, s, 0,
0, 1, 0, 0,
- s, 0, c, 0,
0, 0, 0, 1
);
return this;
makeRotationZ( theta ) {
this.set(
c, - s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
);
return this;
// Based on http://www.gamedev.net/reference/articles/article1199.asp
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( x, y, z ) {
this.set(
x, 0, 0, 0,
0, y, 0, 0,
0, 0, z, 0,
0, 0, 0, 1
);
return this;
this.set(
1, yx, zx, 0,
xy, 1, zy, 0,
xz, yz, 1, 0,
0, 0, 0, 1
);
return this;
const te = this.elements;
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;
const te = this.elements;
position.x = te[ 12 ];
position.y = te[ 13 ];
position.z = te[ 14 ];
_m1$4.elements[ 0 ] *= invSX;
_m1$4.elements[ 1 ] *= invSX;
_m1$4.elements[ 2 ] *= invSX;
_m1$4.elements[ 4 ] *= invSY;
_m1$4.elements[ 5 ] *= invSY;
_m1$4.elements[ 6 ] *= invSY;
_m1$4.elements[ 8 ] *= invSZ;
_m1$4.elements[ 9 ] *= invSZ;
_m1$4.elements[ 10 ] *= invSZ;
quaternion.setFromRotationMatrix( _m1$4 );
scale.x = sx;
scale.y = sy;
scale.z = sz;
return this;
const te = this.elements;
const x = 2 * near / ( right - left );
const y = 2 * near / ( top - bottom );
let c, d;
} else {
return this;
const te = this.elements;
const w = 1.0 / ( right - left );
const h = 1.0 / ( top - bottom );
const p = 1.0 / ( far - near );
z = ( far + near ) * p;
zInv = - 2 * p;
z = near * p;
zInv = - 1 * p;
} else {
return this;
equals( matrix ) {
const te = this.elements;
const me = matrix.elements;
return true;
return this;
}
toArray( array = [], offset = 0 ) {
const te = this.elements;
return array;
class Euler {
this.isEuler = true;
this._x = x;
this._y = y;
this._z = z;
this._order = order;
get x() {
return this._x;
}
set x( value ) {
this._x = value;
this._onChangeCallback();
get y() {
return this._y;
set y( value ) {
this._y = value;
this._onChangeCallback();
get z() {
return this._z;
set z( value ) {
this._z = value;
this._onChangeCallback();
get order() {
return this._order;
this._order = value;
this._onChangeCallback();
this._x = x;
this._y = y;
this._z = z;
this._order = order;
this._onChangeCallback();
return this;
}
clone() {
copy( euler ) {
this._x = euler._x;
this._y = euler._y;
this._z = euler._z;
this._order = euler._order;
this._onChangeCallback();
return this;
const te = m.elements;
const m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];
const m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];
const m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];
switch ( order ) {
case 'XYZ':
} else {
break;
case 'YXZ':
break;
case 'ZXY':
} else {
this._y = 0;
this._z = Math.atan2( m21, m11 );
break;
case 'ZYX':
} else {
this._x = 0;
this._z = Math.atan2( - m12, m22 );
break;
case 'YZX':
} else {
this._x = 0;
this._y = Math.atan2( m13, m33 );
}
break;
case 'XZY':
} else {
break;
default:
this._order = order;
return this;
_matrix$2.makeRotationFromQuaternion( q );
reorder( newOrder ) {
_quaternion$3.setFromEuler( this );
equals( euler ) {
fromArray( 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;
return array;
_onChange( callback ) {
this._onChangeCallback = callback;
return this;
_onChangeCallback() {}
*[ Symbol.iterator ]() {
yield this._x;
yield this._y;
yield this._z;
yield this._order;
Euler.DEFAULT_ORDER = 'XYZ';
class Layers {
constructor() {
this.mask = 1 | 0;
set( channel ) {
enable( channel ) {
enableAll() {
this.mask = 0xffffffff | 0;
toggle( channel ) {
disable( channel ) {
disableAll() {
this.mask = 0;
test( layers ) {
isEnabled( channel ) {
let _object3DId = 0;
constructor() {
super();
this.isObject3D = true;
this.uuid = generateUUID();
this.name = '';
this.type = 'Object3D';
this.parent = null;
this.children = [];
this.up = Object3D.DEFAULT_UP.clone();
function onRotationChange() {
function onQuaternionChange() {
rotation._onChange( onRotationChange );
quaternion._onChange( onQuaternionChange );
Object.defineProperties( this, {
position: {
configurable: true,
enumerable: true,
value: position
},
rotation: {
configurable: true,
enumerable: true,
value: rotation
},
quaternion: {
configurable: true,
enumerable: true,
value: quaternion
},
scale: {
configurable: true,
enumerable: true,
value: scale
},
modelViewMatrix: {
value: new Matrix4()
},
normalMatrix: {
value: new Matrix3()
}
} );
this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;
this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE;
// checked by the renderer
this.matrixWorldNeedsUpdate = false;
this.castShadow = false;
this.receiveShadow = false;
this.frustumCulled = true;
this.renderOrder = 0;
this.animations = [];
this.userData = {};
applyMatrix4( matrix ) {
if ( this.matrixAutoUpdate ) this.updateMatrix();
this.matrix.premultiply( matrix );
applyQuaternion( q ) {
this.quaternion.premultiply( q );
return this;
setRotationFromEuler( euler ) {
setRotationFromMatrix( m ) {
this.quaternion.setFromRotationMatrix( m );
setRotationFromQuaternion( q ) {
// assumes q is normalized
this.quaternion.copy( q );
this.quaternion.multiply( _q1 );
return this;
this.quaternion.premultiply( _q1 );
return this;
rotateX( angle ) {
rotateY( angle ) {
rotateZ( angle ) {
return this;
translateX( distance ) {
translateY( distance ) {
translateZ( distance ) {
localToWorld( vector ) {
worldToLocal( vector ) {
lookAt( x, y, z ) {
if ( x.isVector3 ) {
_target.copy( x );
} else {
_target.set( x, y, z );
_position$3.setFromMatrixPosition( this.matrixWorld );
if ( this.isCamera || this.isLight ) {
} else {
this.quaternion.setFromRotationMatrix( _m1$3 );
if ( parent ) {
_m1$3.extractRotation( parent.matrixWorld );
_q1.setFromRotationMatrix( _m1$3 );
this.quaternion.premultiply( _q1.invert() );
add( object ) {
if ( arguments.length > 1 ) {
this.add( arguments[ i ] );
return this;
object.removeFromParent();
object.parent = this;
this.children.push( object );
object.dispatchEvent( _addedEvent );
_childaddedEvent.child = object;
this.dispatchEvent( _childaddedEvent );
_childaddedEvent.child = null;
} else {
return this;
remove( object ) {
if ( arguments.length > 1 ) {
return this;
if ( index !== - 1 ) {
object.parent = null;
this.children.splice( index, 1 );
object.dispatchEvent( _removedEvent );
_childremovedEvent.child = object;
this.dispatchEvent( _childremovedEvent );
_childremovedEvent.child = null;
return this;
removeFromParent() {
parent.remove( this );
return this;
clear() {
attach( object ) {
// Note: This method does not support scene graphs having non-
uniformly-scaled nodes(s)
_m1$3.multiply( object.parent.matrixWorld );
object.applyMatrix4( _m1$3 );
object.removeFromParent();
object.parent = this;
this.children.push( object );
object.dispatchEvent( _addedEvent );
_childaddedEvent.child = object;
this.dispatchEvent( _childaddedEvent );
_childaddedEvent.child = null;
return this;
getObjectById( id ) {
getObjectByName( name ) {
return object;
return undefined;
}
getObjectsByProperty( name, value, result = [] ) {
return result;
getWorldPosition( target ) {
getWorldQuaternion( target ) {
return target;
getWorldScale( target ) {
return target;
getWorldDirection( target ) {
const e = this.matrixWorld.elements;
traverse( callback ) {
callback( this );
const children = this.children;
traverseVisible( callback ) {
callback( this );
traverseAncestors( callback ) {
callback( parent );
parent.traverseAncestors( callback );
updateMatrix() {
this.matrixWorldNeedsUpdate = true;
updateMatrixWorld( force ) {
if ( this.matrixAutoUpdate ) this.updateMatrix();
if ( this.matrixWorldNeedsUpdate || force ) {
} else {
this.matrixWorldNeedsUpdate = false;
force = true;
child.updateMatrixWorld( force );
if ( this.matrixAutoUpdate ) this.updateMatrix();
this.matrixWorld.copy( this.matrix );
} else {
this.matrixWorld.multiplyMatrices( this.parent.matrixWorld,
this.matrix );
toJSON( meta ) {
output.metadata = {
version: 4.6,
type: 'Object',
generator: 'Object3D.toJSON'
};
object.uuid = this.uuid;
object.type = this.type;
object.layers = this.layers.mask;
object.matrix = this.matrix.toArray();
object.up = this.up.toArray();
if ( this.isInstancedMesh ) {
object.type = 'InstancedMesh';
object.count = this.count;
object.instanceMatrix = this.instanceMatrix.toJSON();
if ( this.instanceColor !== null ) object.instanceColor =
this.instanceColor.toJSON();
if ( this.isBatchedMesh ) {
object.type = 'BatchedMesh';
object.perObjectFrustumCulled = this.perObjectFrustumCulled;
object.sortObjects = this.sortObjects;
object.drawRanges = this._drawRanges;
object.reservedRanges = this._reservedRanges;
object.visibility = this._visibility;
object.active = this._active;
object.bounds = this._bounds.map( bound => ( {
boxInitialized: bound.boxInitialized,
boxMin: bound.box.min.toArray(),
boxMax: bound.box.max.toArray(),
sphereInitialized: bound.sphereInitialized,
sphereRadius: bound.sphere.radius,
sphereCenter: bound.sphere.center.toArray()
} ) );
object.maxInstanceCount = this._maxInstanceCount;
object.maxVertexCount = this._maxVertexCount;
object.maxIndexCount = this._maxIndexCount;
object.geometryInitialized = this._geometryInitialized;
object.geometryCount = this._geometryCount;
object.boundingBox = {
min: object.boundingBox.min.toArray(),
max: object.boundingBox.max.toArray()
};
//
return element.uuid;
if ( this.isScene ) {
if ( this.background ) {
if ( this.background.isColor ) {
object.background = this.background.toJSON();
} else if ( this.background.isTexture ) {
object.background =
this.background.toJSON( meta ).uuid;
if ( Array.isArray( shapes ) ) {
} else {
if ( this.isSkinnedMesh ) {
object.bindMode = this.bindMode;
object.bindMatrix = this.bindMatrix.toArray();
object.skeleton = this.skeleton.uuid;
if ( Array.isArray( this.material ) ) {
object.material = uuids;
} else {
//
if ( this.children.length > 0 ) {
object.children = [];
//
if ( this.animations.length > 0 ) {
object.animations = [];
if ( isRootObject ) {
output.object = object;
return output;
return values;
clone( recursive ) {
this.name = source.name;
this.up.copy( source.up );
this.position.copy( source.position );
this.rotation.order = source.rotation.order;
this.quaternion.copy( source.quaternion );
this.scale.copy( source.scale );
this.matrix.copy( source.matrix );
this.matrixWorld.copy( source.matrixWorld );
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
this.layers.mask = source.layers.mask;
this.visible = source.visible;
this.castShadow = source.castShadow;
this.receiveShadow = source.receiveShadow;
this.frustumCulled = source.frustumCulled;
this.renderOrder = source.renderOrder;
this.animations = source.animations.slice();
return this;
class Triangle {
this.a = a;
this.b = b;
this.c = c;
target.subVectors( c, b );
_v0$2.subVectors( a, b );
target.cross( _v0$2 );
const targetLengthSq = target.lengthSq();
if ( targetLengthSq > 0 ) {
return target.set( 0, 0, 0 );
_v0$2.subVectors( c, a );
_v1$3.subVectors( b, a );
_v2$2.subVectors( point, a );
target.set( 0, 0, 0 );
return null;
return false;
}
static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {
target.x = 0;
target.y = 0;
if ( 'z' in target ) target.z = 0;
if ( 'w' in target ) target.w = 0;
return null;
target.setScalar( 0 );
target.addScaledVector( v1, _v3$2.x );
target.addScaledVector( v2, _v3$2.y );
target.addScaledVector( v3, _v3$2.z );
return target;
_v40.setScalar( 0 );
_v41.setScalar( 0 );
_v42.setScalar( 0 );
_v40.fromBufferAttribute( attr, i1 );
_v41.fromBufferAttribute( attr, i2 );
_v42.fromBufferAttribute( attr, i3 );
target.setScalar( 0 );
target.addScaledVector( _v40, barycoord.x );
target.addScaledVector( _v41, barycoord.y );
target.addScaledVector( _v42, barycoord.z );
return target;
_v0$2.subVectors( c, b );
_v1$3.subVectors( a, b );
set( a, b, c ) {
this.a.copy( a );
this.b.copy( b );
this.c.copy( c );
return this;
}
setFromPointsAndIndices( points, i0, i1, i2 ) {
this.a.copy( points[ i0 ] );
this.b.copy( points[ i1 ] );
this.c.copy( points[ i2 ] );
return this;
this.a.fromBufferAttribute( attribute, i0 );
this.b.fromBufferAttribute( attribute, i1 );
this.c.fromBufferAttribute( attribute, i2 );
return this;
clone() {
copy( triangle ) {
this.a.copy( triangle.a );
this.b.copy( triangle.b );
this.c.copy( triangle.c );
return this;
getArea() {
getMidpoint( target ) {
getNormal( target ) {
}
getPlane( target ) {
containsPoint( point ) {
isFrontFacing( direction ) {
intersectsBox( box ) {
closestPointToPoint( p, target ) {
_vab.subVectors( b, a );
_vac.subVectors( c, a );
_vap.subVectors( p, a );
const d1 = _vab.dot( _vap );
const d2 = _vac.dot( _vap );
if ( d1 <= 0 && d2 <= 0 ) {
_vbp.subVectors( p, b );
const d3 = _vab.dot( _vbp );
const d4 = _vac.dot( _vbp );
if ( d3 >= 0 && d4 <= d3 ) {
const 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 );
const d5 = _vab.dot( _vcp );
const d6 = _vac.dot( _vcp );
if ( d6 >= 0 && d5 <= d6 ) {
const 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 );
const 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
const 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( triangle ) {
const _hslA = { h: 0, s: 0, l: 0 };
const _hslB = { h: 0, s: 0, l: 0 };
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;
class Color {
constructor( r, g, b ) {
this.isColor = true;
this.r = 1;
this.g = 1;
this.b = 1;
return this.set( r, g, b );
set( r, g, b ) {
const value = r;
this.copy( value );
this.setHex( value );
this.setStyle( value );
} else {
this.setRGB( r, g, b );
}
return this;
setScalar( scalar ) {
this.r = scalar;
this.g = scalar;
this.b = scalar;
return this;
return this;
this.r = r;
this.g = g;
this.b = b;
return this;
if ( s === 0 ) {
} else {
this.r = hue2rgb( q, p, h + 1 / 3 );
this.g = hue2rgb( q, p, h );
this.b = hue2rgb( q, p, h - 1 / 3 );
return this;
let m;
if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) {
// rgb / hsl
let color;
const name = m[ 1 ];
const components = m[ 2 ];
switch ( name ) {
case 'rgb':
case 'rgba':
if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\
s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
// rgb(255,0,0) rgba(255,0,0,0.5)
handleAlpha( color[ 4 ] );
return this.setRGB(
Math.min( 255, parseInt( color[ 1 ], 10 )
) / 255,
Math.min( 255, parseInt( color[ 2 ], 10 )
) / 255,
Math.min( 255, parseInt( color[ 3 ], 10 )
) / 255,
colorSpace
);
}
if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\
%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
handleAlpha( color[ 4 ] );
return this.setRGB(
Math.min( 100, parseInt( color[ 1 ], 10 )
) / 100,
Math.min( 100, parseInt( color[ 2 ], 10 )
) / 100,
Math.min( 100, parseInt( color[ 3 ], 10 )
) / 100,
colorSpace
);
break;
case 'hsl':
case 'hsla':
if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\
s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) {
// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
handleAlpha( color[ 4 ] );
return this.setHSL(
parseFloat( color[ 1 ] ) / 360,
parseFloat( color[ 2 ] ) / 100,
parseFloat( color[ 3 ] ) / 100,
colorSpace
);
break;
default:
// hex color
const hex = m[ 1 ];
const size = hex.length;
if ( size === 3 ) {
// #ff0
return this.setRGB(
parseInt( hex.charAt( 0 ), 16 ) / 15,
parseInt( hex.charAt( 1 ), 16 ) / 15,
parseInt( hex.charAt( 2 ), 16 ) / 15,
colorSpace
);
// #ff0000
return this.setHex( parseInt( hex, 16 ), colorSpace );
} else {
return this;
// color keywords
const hex = _colorKeywords[ style.toLowerCase() ];
// red
this.setHex( hex, colorSpace );
} else {
// unknown color
console.warn( 'THREE.Color: Unknown color ' + style );
return this;
clone() {
copy( color ) {
this.r = color.r;
this.g = color.g;
this.b = color.b;
return this;
copySRGBToLinear( color ) {
return this;
copyLinearToSRGB( color ) {
return this;
convertSRGBToLinear() {
this.copySRGBToLinear( this );
return this;
convertLinearToSRGB() {
this.copyLinearToSRGB( this );
return this;
hue = 0;
saturation = 0;
} else {
switch ( max ) {
hue /= 6;
target.h = hue;
target.s = saturation;
target.l = lightness;
return target;
target.r = _color.r;
target.g = _color.g;
target.b = _color.b;
return target;
offsetHSL( h, s, l ) {
this.getHSL( _hslA );
add( color ) {
this.r += color.r;
this.g += color.g;
this.b += color.b;
return this;
return this;
addScalar( s ) {
this.r += s;
this.g += s;
this.b += s;
return this;
sub( color ) {
return this;
multiply( color ) {
this.r *= color.r;
this.g *= color.g;
this.b *= color.b;
return this;
multiplyScalar( s ) {
this.r *= s;
this.g *= s;
this.b *= s;
return this;
return this;
return this;
this.getHSL( _hslA );
color.getHSL( _hslB );
const h = lerp( _hslA.h, _hslB.h, alpha );
const s = lerp( _hslA.s, _hslB.s, alpha );
const l = lerp( _hslA.l, _hslB.l, alpha );
this.setHSL( h, s, l );
return this;
setFromVector3( v ) {
this.r = v.x;
this.g = v.y;
this.b = v.z;
return this;
applyMatrix3( m ) {
this.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;
this.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;
this.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;
return this;
equals( c ) {
return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );
return this;
return array;
}
fromBufferAttribute( attribute, index ) {
return this;
toJSON() {
return this.getHex();
*[ Symbol.iterator ]() {
yield this.r;
yield this.g;
yield this.b;
Color.NAMES = _colorKeywords;
let _materialId = 0;
constructor() {
super();
this.isMaterial = true;
this.uuid = generateUUID();
this.name = '';
this.type = 'Material';
this.blending = NormalBlending;
this.side = FrontSide;
this.vertexColors = false;
this.opacity = 1;
this.transparent = false;
this.alphaHash = false;
this.blendSrc = SrcAlphaFactor;
this.blendDst = OneMinusSrcAlphaFactor;
this.blendEquation = AddEquation;
this.blendSrcAlpha = null;
this.blendDstAlpha = null;
this.blendEquationAlpha = null;
this.blendColor = new Color( 0, 0, 0 );
this.blendAlpha = 0;
this.depthFunc = LessEqualDepth;
this.depthTest = true;
this.depthWrite = true;
this.stencilWriteMask = 0xff;
this.stencilFunc = AlwaysStencilFunc;
this.stencilRef = 0;
this.stencilFuncMask = 0xff;
this.stencilFail = KeepStencilOp;
this.stencilZFail = KeepStencilOp;
this.stencilZPass = KeepStencilOp;
this.stencilWrite = false;
this.clippingPlanes = null;
this.clipIntersection = false;
this.clipShadows = false;
this.shadowSide = null;
this.colorWrite = true;
this.polygonOffset = false;
this.polygonOffsetFactor = 0;
this.polygonOffsetUnits = 0;
this.dithering = false;
this.alphaToCoverage = false;
this.premultipliedAlpha = false;
this.forceSinglePass = false;
this.visible = true;
this.toneMapped = true;
this.userData = {};
this.version = 0;
this._alphaTest = 0;
get alphaTest() {
return this._alphaTest;
this.version ++;
this._alphaTest = value;
customProgramCacheKey() {
return this.onBeforeCompile.toString();
setValues( values ) {
currentValue.set( newValue );
currentValue.copy( newValue );
} else {
this[ key ] = newValue;
toJSON( meta ) {
if ( isRootObject ) {
meta = {
textures: {},
images: {}
};
const data = {
metadata: {
version: 4.6,
type: 'Material',
generator: 'Material.toJSON'
}
};
data.clearcoatRoughnessMap =
this.clearcoatRoughnessMap.toJSON( meta ).uuid;
data.clearcoatNormalMap =
this.clearcoatNormalMap.toJSON( meta ).uuid;
data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
if ( this.iridescenceThicknessMap &&
this.iridescenceThicknessMap.isTexture ) {
data.iridescenceThicknessMap =
this.iridescenceThicknessMap.toJSON( meta ).uuid;
}
if ( this.map && this.map.isTexture ) data.map =
this.map.toJSON( meta ).uuid;
if ( this.matcap && this.matcap.isTexture ) data.matcap =
this.matcap.toJSON( meta ).uuid;
if ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap =
this.alphaMap.toJSON( meta ).uuid;
// rotation (SpriteMaterial)
if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation
= this.rotation;
return values;
if ( isRootObject ) {
return data;
clone() {
copy( source ) {
this.name = source.name;
this.blending = source.blending;
this.side = source.side;
this.vertexColors = source.vertexColors;
this.opacity = source.opacity;
this.transparent = source.transparent;
this.blendSrc = source.blendSrc;
this.blendDst = source.blendDst;
this.blendEquation = source.blendEquation;
this.blendSrcAlpha = source.blendSrcAlpha;
this.blendDstAlpha = source.blendDstAlpha;
this.blendEquationAlpha = source.blendEquationAlpha;
this.blendColor.copy( source.blendColor );
this.blendAlpha = source.blendAlpha;
this.depthFunc = source.depthFunc;
this.depthTest = source.depthTest;
this.depthWrite = source.depthWrite;
this.stencilWriteMask = source.stencilWriteMask;
this.stencilFunc = source.stencilFunc;
this.stencilRef = source.stencilRef;
this.stencilFuncMask = source.stencilFuncMask;
this.stencilFail = source.stencilFail;
this.stencilZFail = source.stencilZFail;
this.stencilZPass = source.stencilZPass;
this.stencilWrite = source.stencilWrite;
const n = srcPlanes.length;
dstPlanes = new Array( n );
this.clippingPlanes = dstPlanes;
this.clipIntersection = source.clipIntersection;
this.clipShadows = source.clipShadows;
this.shadowSide = source.shadowSide;
this.colorWrite = source.colorWrite;
this.precision = source.precision;
this.polygonOffset = source.polygonOffset;
this.polygonOffsetFactor = source.polygonOffsetFactor;
this.polygonOffsetUnits = source.polygonOffsetUnits;
this.dithering = source.dithering;
this.alphaTest = source.alphaTest;
this.alphaHash = source.alphaHash;
this.alphaToCoverage = source.alphaToCoverage;
this.premultipliedAlpha = source.premultipliedAlpha;
this.forceSinglePass = source.forceSinglePass;
this.visible = source.visible;
this.toneMapped = source.toneMapped;
return this;
dispose() {
constructor( parameters ) {
super();
this.isMeshBasicMaterial = true;
this.type = 'MeshBasicMaterial';
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.fog = source.fog;
return this;
function _generateTables() {
const e = i - 127;
if ( e < - 27 ) {
baseTable[ i ] = 0x0000;
baseTable[ i | 0x100 ] = 0x8000;
shiftTable[ i ] = 24;
shiftTable[ i | 0x100 ] = 24;
} else if ( e < - 14 ) {
// normal number
} else if ( e <= 15 ) {
baseTable[ i ] = 0x7c00;
baseTable[ i | 0x100 ] = 0xfc00;
shiftTable[ i ] = 24;
shiftTable[ i | 0x100 ] = 24;
} else {
baseTable[ i ] = 0x7c00;
baseTable[ i | 0x100 ] = 0xfc00;
shiftTable[ i ] = 13;
shiftTable[ i | 0x100 ] = 13;
}
// float16 to float32 helpers
// normalized
while ( ( m & 0x00800000 ) === 0 ) {
m <<= 1;
e -= 0x00800000; // decrement exponent
mantissaTable[ i ] = m | e;
exponentTable[ 31 ] = 0x47800000;
exponentTable[ 32 ] = 0x80000000;
exponentTable[ 63 ] = 0xc7800000;
if ( i !== 32 ) {
offsetTable[ i ] = 1024;
}
return {
floatView: floatView,
uint32View: uint32View,
baseTable: baseTable,
shiftTable: shiftTable,
mantissaTable: mantissaTable,
exponentTable: exponentTable,
offsetTable: offsetTable
};
// float32 to float16
_tables.floatView[ 0 ] = val;
const f = _tables.uint32View[ 0 ];
const e = ( f >> 23 ) & 0x1ff;
return _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e
] );
// float16 to float32
const DataUtils = {
toHalfFloat: toHalfFloat,
fromHalfFloat: fromHalfFloat,
};
class BufferAttribute {
if ( Array.isArray( array ) ) {
}
this.isBufferAttribute = true;
this.name = '';
this.array = array;
this.itemSize = itemSize;
this.count = array !== undefined ? array.length / itemSize : 0;
this.normalized = normalized;
this.usage = StaticDrawUsage;
this.updateRanges = [];
this.gpuType = FloatType;
this.version = 0;
onUploadCallback() {}
setUsage( value ) {
this.usage = value;
return this;
clearUpdateRanges() {
this.updateRanges.length = 0;
copy( source ) {
this.name = source.name;
this.array = new source.array.constructor( source.array );
this.itemSize = source.itemSize;
this.count = source.count;
this.normalized = source.normalized;
this.usage = source.usage;
this.gpuType = source.gpuType;
return this;
}
copyAt( index1, attribute, index2 ) {
index1 *= this.itemSize;
index2 *= attribute.itemSize;
return this;
copyArray( array ) {
this.array.set( array );
return this;
applyMatrix3( m ) {
if ( this.itemSize === 2 ) {
_vector2$1.fromBufferAttribute( this, i );
_vector2$1.applyMatrix3( m );
_vector$9.fromBufferAttribute( this, i );
_vector$9.applyMatrix3( m );
return this;
applyMatrix4( m ) {
_vector$9.fromBufferAttribute( this, i );
_vector$9.applyMatrix4( m );
return this;
applyNormalMatrix( m ) {
_vector$9.fromBufferAttribute( this, i );
_vector$9.applyNormalMatrix( m );
return this;
transformDirection( m ) {
_vector$9.fromBufferAttribute( this, i );
_vector$9.transformDirection( m );
return this;
return this;
return value;
}
return this;
getX( index ) {
return x;
setX( index, x ) {
return this;
getY( index ) {
return y;
setY( index, y ) {
return this;
getZ( index ) {
setZ( index, z ) {
return this;
getW( index ) {
return w;
setW( index, w ) {
return this;
setXY( index, x, y ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
this.array[ index + 0 ] = x;
this.array[ index + 1 ] = y;
return this;
setXYZ( index, x, y, z ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
this.array[ index + 0 ] = x;
this.array[ index + 1 ] = y;
this.array[ index + 2 ] = z;
return this;
setXYZW( index, x, y, z, w ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
w = normalize( w, this.array );
this.array[ index + 0 ] = x;
this.array[ index + 1 ] = y;
this.array[ index + 2 ] = z;
this.array[ index + 3 ] = w;
return this;
onUpload( callback ) {
this.onUploadCallback = callback;
return this;
clone() {
toJSON() {
const data = {
itemSize: this.itemSize,
type: this.array.constructor.name,
array: Array.from( this.array ),
normalized: this.normalized
};
return data;
//
}
class Int32BufferAttribute extends BufferAttribute {
this.isFloat16BufferAttribute = true;
getX( index ) {
return x;
setX( index, x ) {
return this;
getY( index ) {
return y;
}
setY( index, y ) {
return this;
getZ( index ) {
return z;
setZ( index, z ) {
return this;
getW( index ) {
return w;
setW( index, w ) {
return this;
setXY( index, x, y ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
return this;
setXYZ( index, x, y, z ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
return this;
setXYZW( index, x, y, z, w ) {
index *= this.itemSize;
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
w = normalize( w, this.array );
return this;
let _id$2 = 0;
constructor() {
super();
this.isBufferGeometry = true;
this.uuid = generateUUID();
this.name = '';
this.type = 'BufferGeometry';
this.index = null;
this.indirect = null;
this.attributes = {};
this.morphAttributes = {};
this.morphTargetsRelative = false;
this.groups = [];
this.boundingBox = null;
this.boundingSphere = null;
this.userData = {};
getIndex() {
return this.index;
setIndex( index ) {
if ( Array.isArray( index ) ) {
this.index = new ( arrayNeedsUint32( index ) ?
Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );
} else {
this.index = index;
return this;
setIndirect( indirect ) {
this.indirect = indirect;
return this;
getIndirect() {
return this.indirect;
getAttribute( name ) {
return this;
deleteAttribute( name ) {
return this;
hasAttribute( name ) {
this.groups.push( {
start: start,
count: count,
materialIndex: materialIndex
} );
clearGroups() {
this.groups = [];
this.drawRange.start = start;
this.drawRange.count = count;
applyMatrix4( matrix ) {
position.applyMatrix4( matrix );
position.needsUpdate = true;
normal.applyNormalMatrix( normalMatrix );
normal.needsUpdate = true;
tangent.transformDirection( matrix );
tangent.needsUpdate = true;
this.computeBoundingBox();
}
this.computeBoundingSphere();
return this;
applyQuaternion( q ) {
_m1$2.makeRotationFromQuaternion( q );
this.applyMatrix4( _m1$2 );
return this;
rotateX( angle ) {
_m1$2.makeRotationX( angle );
this.applyMatrix4( _m1$2 );
return this;
rotateY( angle ) {
_m1$2.makeRotationY( angle );
this.applyMatrix4( _m1$2 );
return this;
rotateZ( angle ) {
_m1$2.makeRotationZ( angle );
this.applyMatrix4( _m1$2 );
return this;
translate( x, y, z ) {
// translate geometry
_m1$2.makeTranslation( x, y, z );
this.applyMatrix4( _m1$2 );
return this;
scale( x, y, z ) {
// scale geometry
_m1$2.makeScale( x, y, z );
this.applyMatrix4( _m1$2 );
return this;
lookAt( vector ) {
_obj.lookAt( vector );
_obj.updateMatrix();
this.applyMatrix4( _obj.matrix );
return this;
center() {
this.computeBoundingBox();
return this;
setFromPoints( points ) {
} else {
positionAttribute.needsUpdate = true;
return this;
computeBoundingBox() {
console.error( 'THREE.BufferGeometry.computeBoundingBox():
GLBufferAttribute requires a manual bounding box.', this );
this.boundingBox.set(
new Vector3( - Infinity, - Infinity, - Infinity ),
new Vector3( + Infinity, + Infinity, + Infinity )
);
return;
}
if ( position !== undefined ) {
this.boundingBox.setFromBufferAttribute( position );
if ( morphAttributesPosition ) {
if ( this.morphTargetsRelative ) {
_vector$8.addVectors( this.boundingBox.min,
_box$2.min );
this.boundingBox.expandByPoint( _vector$8 );
_vector$8.addVectors( this.boundingBox.max,
_box$2.max );
this.boundingBox.expandByPoint( _vector$8 );
} else {
this.boundingBox.expandByPoint( _box$2.min );
this.boundingBox.expandByPoint( _box$2.max );
} else {
this.boundingBox.makeEmpty();
console.error( 'THREE.BufferGeometry.computeBoundingBox():
Computed min/max have NaN values. The "position" attribute is likely to have NaN
values.', this );
computeBoundingSphere() {
}
const position = this.attributes.position;
const morphAttributesPosition = this.morphAttributes.position;
console.error( 'THREE.BufferGeometry.computeBoundingSphere():
GLBufferAttribute requires a manual bounding sphere.', this );
return;
if ( position ) {
_box$2.setFromBufferAttribute( position );
if ( morphAttributesPosition ) {
_boxMorphTargets.setFromBufferAttribute( morphAttribute );
if ( this.morphTargetsRelative ) {
_vector$8.addVectors( _box$2.min,
_boxMorphTargets.min );
_box$2.expandByPoint( _vector$8 );
_vector$8.addVectors( _box$2.max,
_boxMorphTargets.max );
_box$2.expandByPoint( _vector$8 );
} else {
_box$2.expandByPoint( _boxMorphTargets.min );
_box$2.expandByPoint( _boxMorphTargets.max );
_box$2.getCenter( center );
let maxRadiusSq = 0;
_vector$8.fromBufferAttribute( position, i );
if ( morphAttributesPosition ) {
_vector$8.fromBufferAttribute( morphAttribute,
j );
if ( morphTargetsRelative ) {
_offset.fromBufferAttribute( position,
j );
_vector$8.add( _offset );
if ( isNaN( this.boundingSphere.radius ) ) {
}
}
computeTangents() {
// based on http://www.terathon.com/code/tangent.html
// (per vertex tangents)
function handleTriangle( a, b, c ) {
vA.fromBufferAttribute( positionAttribute, a );
vB.fromBufferAttribute( positionAttribute, b );
vC.fromBufferAttribute( positionAttribute, c );
uvA.fromBufferAttribute( uvAttribute, a );
uvB.fromBufferAttribute( uvAttribute, b );
uvC.fromBufferAttribute( uvAttribute, c );
vB.sub( vA );
vC.sub( vA );
uvB.sub( uvA );
uvC.sub( uvA );
if ( ! isFinite( r ) ) return;
if ( groups.length === 0 ) {
groups = [ {
start: 0,
count: index.count
} ];
handleTriangle(
index.getX( j + 0 ),
index.getX( j + 1 ),
index.getX( j + 2 )
);
}
function handleVertex( v ) {
n.fromBufferAttribute( normalAttribute, v );
n2.copy( n );
const t = tan1[ v ];
// Gram-Schmidt orthogonalize
tmp.copy( t );
tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
// Calculate handedness
tmp2.crossVectors( n2, t );
const test = tmp2.dot( tan2[ v ] );
const w = ( test < 0.0 ) ? - 1.0 : 1.0;
handleVertex( index.getX( j + 0 ) );
handleVertex( index.getX( j + 1 ) );
handleVertex( index.getX( j + 2 ) );
computeVertexNormals() {
} else {
normalAttribute.setXYZ( i, 0, 0, 0 );
// indexed elements
if ( index ) {
const vA = index.getX( i + 0 );
const vB = index.getX( i + 1 );
const vC = index.getX( i + 2 );
pA.fromBufferAttribute( positionAttribute, vA );
pB.fromBufferAttribute( positionAttribute, vB );
pC.fromBufferAttribute( positionAttribute, vC );
cb.subVectors( pC, pB );
ab.subVectors( pA, pB );
cb.cross( ab );
nA.fromBufferAttribute( normalAttribute, vA );
nB.fromBufferAttribute( normalAttribute, vB );
nC.fromBufferAttribute( normalAttribute, vC );
nA.add( cb );
nB.add( cb );
nC.add( cb );
} else {
pA.fromBufferAttribute( positionAttribute, i + 0 );
pB.fromBufferAttribute( positionAttribute, i + 1 );
pC.fromBufferAttribute( positionAttribute, i + 2 );
cb.subVectors( pC, pB );
ab.subVectors( pA, pB );
cb.cross( ab );
this.normalizeNormals();
normalAttribute.needsUpdate = true;
normalizeNormals() {
_vector$8.fromBufferAttribute( normals, i );
_vector$8.normalize();
toNonIndexed() {
if ( attribute.isInterleavedBufferAttribute ) {
index = indices[ i ] * attribute.data.stride +
attribute.offset;
} else {
//
console.warn( 'THREE.BufferGeometry.toNonIndexed():
BufferGeometry is already non-indexed.' );
return this;
// attributes
// morph attributes
morphArray.push( newAttribute );
geometry2.morphTargetsRelative = this.morphTargetsRelative;
// groups
return geometry2;
toJSON() {
const data = {
metadata: {
version: 4.6,
type: 'BufferGeometry',
generator: 'BufferGeometry.toJSON'
}
};
data.uuid = this.uuid;
data.type = this.type;
if ( this.name !== '' ) data.name = this.name;
if ( Object.keys( this.userData ).length > 0 ) data.userData =
this.userData;
return data;
// for simplicity the code assumes attributes are not shared across
geometries, see #15811
data.data = { attributes: {} };
data.data.index = {
type: index.array.constructor.name,
array: Array.prototype.slice.call( index.array )
};
if ( array.length > 0 ) {
hasMorphAttributes = true;
}
if ( hasMorphAttributes ) {
data.data.morphAttributes = morphAttributes;
data.data.morphTargetsRelative = this.morphTargetsRelative;
if ( groups.length > 0 ) {
data.data.boundingSphere = {
center: boundingSphere.center.toArray(),
radius: boundingSphere.radius
};
return data;
clone() {
copy( source ) {
// reset
this.index = null;
this.attributes = {};
this.morphAttributes = {};
this.groups = [];
this.boundingBox = null;
this.boundingSphere = null;
// name
this.name = source.name;
// index
// attributes
// morph attributes
this.morphTargetsRelative = source.morphTargetsRelative;
// groups
// bounding box
this.boundingBox = boundingBox.clone();
}
// bounding sphere
this.boundingSphere = boundingSphere.clone();
// draw range
this.drawRange.start = source.drawRange.start;
this.drawRange.count = source.drawRange.count;
// user data
this.userData = source.userData;
return this;
dispose() {
super();
this.isMesh = true;
this.type = 'Mesh';
this.geometry = geometry;
this.material = material;
this.updateMorphTargets();
this.morphTargetInfluences =
source.morphTargetInfluences.slice();
return this;
updateMorphTargets() {
if ( keys.length > 0 ) {
this.morphTargetInfluences = [];
this.morphTargetDictionary = {};
this.morphTargetInfluences.push( 0 );
this.morphTargetDictionary[ name ] = m;
}
}
_morphA.set( 0, 0, 0 );
if ( morphTargetsRelative ) {
} else {
target.add( _morphA );
return target;
_sphere$6.copy( geometry.boundingSphere );
_sphere$6.applyMatrix4( matrixWorld );
let intersection;
if ( Array.isArray( material ) ) {
const a = index.getX( j );
const b = index.getX( j + 1 );
const c = index.getX( j + 2 );
if ( intersection ) {
intersection.faceIndex = Math.floor( j /
3 ); // triangle number in indexed buffer semantics
intersection.face.materialIndex =
group.materialIndex;
intersects.push( intersection );
} else {
const a = index.getX( i );
const b = index.getX( i + 1 );
const c = index.getX( i + 2 );
if ( intersection ) {
intersection.faceIndex = Math.floor( i /
3 ); // triangle number in indexed buffer semantics
intersects.push( intersection );
}
if ( Array.isArray( material ) ) {
const a = j;
const b = j + 1;
const c = j + 2;
if ( intersection ) {
intersection.faceIndex = Math.floor( j /
3 ); // triangle number in non-indexed buffer semantics
intersection.face.materialIndex =
group.materialIndex;
intersects.push( intersection );
} else {
const a = i;
const b = i + 1;
const c = i + 2;
if ( intersection ) {
intersection.faceIndex = Math.floor( i /
3 ); // triangle number in non-indexed buffer semantics
intersects.push( intersection );
function checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point )
{
let intersect;
} else {
_intersectionPointWorld.copy( point );
_intersectionPointWorld.applyMatrix4( object.matrixWorld );
return {
distance: distance,
point: _intersectionPointWorld.clone(),
object: object
};
object.getVertexPosition( a, _vA$1 );
object.getVertexPosition( b, _vB$1 );
object.getVertexPosition( c, _vC$1 );
const intersection = checkIntersection$1( object, material, raycaster, ray,
_vA$1, _vB$1, _vC$1, _intersectionPoint );
if ( intersection ) {
if ( uv ) {
if ( uv1 ) {
if ( normal ) {
intersection.normal.multiplyScalar( - 1 );
const face = {
a: a,
b: b,
c: c,
normal: new Vector3(),
materialIndex: 0
};
intersection.face = face;
intersection.barycoord = barycoord;
return intersection;
super();
this.type = 'BoxGeometry';
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
// segments
// buffers
// helper variables
let numberOfVertices = 0;
let groupStart = 0;
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX,
gridY, materialIndex ) {
let vertexCounter = 0;
let groupCount = 0;
vector[ u ] = x * udir;
vector[ v ] = y * vdir;
vector[ w ] = depthHalf;
vector[ u ] = 0;
vector[ v ] = 0;
vector[ w ] = depth > 0 ? 1 : - 1;
// uvs
uvs.push( ix / gridX );
uvs.push( 1 - ( iy / gridY ) );
// counters
vertexCounter += 1;
}
}
// indices
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// increase counter
groupCount += 6;
groupStart += groupCount;
numberOfVertices += vertexCounter;
copy( source ) {
super.copy( source );
return this;
}
static fromJSON( data ) {
/**
* Uniform Utilities
*/
dst[ u ] = {};
if ( property.isRenderTargetTexture ) {
} else {
dst[ u ][ p ] = property.clone();
dst[ u ][ p ] = property.slice();
} else {
dst[ u ][ p ] = property;
return dst;
}
merged[ p ] = tmp[ p ];
return merged;
return dst;
// https://github.com/mrdoob/three.js/pull/23937#issuecomment-
1111067398
return renderer.outputColorSpace;
// https://github.com/mrdoob/three.js/issues/27868
if ( currentRenderTarget.isXRRenderTarget === true ) {
return currentRenderTarget.texture.colorSpace;
return ColorManagement.workingColorSpace;
}
// Legacy
constructor( parameters ) {
super();
this.isShaderMaterial = true;
this.type = 'ShaderMaterial';
this.defines = {};
this.uniforms = {};
this.uniformsGroups = [];
this.vertexShader = default_vertex;
this.fragmentShader = default_fragment;
this.linewidth = 1;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.forceSinglePass = true;
this.extensions = {
clipCullDistance: false, // set to use vertex shader clipping
multiDraw: false // set to use vertex shader multi_draw / enable
gl_DrawID
};
this.index0AttributeName = undefined;
this.uniformsNeedUpdate = false;
this.glslVersion = null;
if ( parameters !== undefined ) {
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.fragmentShader = source.fragmentShader;
this.vertexShader = source.vertexShader;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.fog = source.fog;
this.lights = source.lights;
this.clipping = source.clipping;
this.glslVersion = source.glslVersion;
return this;
toJSON( meta ) {
data.glslVersion = this.glslVersion;
data.uniforms = {};
data.uniforms[ name ] = {
type: 't',
value: value.toJSON( meta ).uuid
};
data.uniforms[ name ] = {
type: 'c',
value: value.getHex()
};
data.uniforms[ name ] = {
type: 'v2',
value: value.toArray()
};
data.uniforms[ name ] = {
type: 'v3',
value: value.toArray()
};
data.uniforms[ name ] = {
type: 'v4',
value: value.toArray()
};
data.uniforms[ name ] = {
type: 'm3',
value: value.toArray()
};
data.uniforms[ name ] = {
type: 'm4',
value: value.toArray()
};
} else {
data.uniforms[ name ] = {
value: value
};
// note: the array variants v2v, v3v, v4v, m4v and tv are
not supported so far
data.vertexShader = this.vertexShader;
data.fragmentShader = this.fragmentShader;
data.lights = this.lights;
data.clipping = this.clipping;
const extensions = {};
return data;
constructor() {
super();
this.isCamera = true;
this.type = 'Camera';
this.coordinateSystem = WebGLCoordinateSystem;
this.matrixWorldInverse.copy( source.matrixWorldInverse );
this.projectionMatrix.copy( source.projectionMatrix );
this.projectionMatrixInverse.copy( source.projectionMatrixInverse );
this.coordinateSystem = source.coordinateSystem;
return this;
getWorldDirection( target ) {
updateMatrixWorld( force ) {
super.updateMatrixWorld( force );
clone() {
super();
this.isPerspectiveCamera = true;
this.type = 'PerspectiveCamera';
this.fov = fov;
this.zoom = 1;
this.near = near;
this.far = far;
this.focus = 10;
this.aspect = aspect;
this.view = null;
this.updateProjectionMatrix();
this.near = source.near;
this.far = source.far;
this.focus = source.focus;
this.aspect = source.aspect;
this.view = source.view === null ? null : Object.assign( {},
source.view );
this.filmGauge = source.filmGauge;
this.filmOffset = source.filmOffset;
return this;
/**
* Sets the FOV by focal length in respect to the current .filmGauge.
*
* The default film gauge is 35, so that the focal length can be specified
for
* a 35mm (full frame) camera.
*
* @param {number} focalLength - Values for focal length and film gauge must
have the same unit.
*/
setFocalLength( focalLength ) {
/**
* Calculates the focal length from the current .fov and .filmGauge.
*
* @returns {number}
*/
getFocalLength() {
getEffectiveFOV() {
}
getFilmWidth() {
getFilmHeight() {
/**
* Computes the 2D bounds of the camera's viewable rectangle at a given
distance along the viewing direction.
* Sets minTarget and maxTarget to the coordinates of the lower-left and
upper-right corners of the view rectangle.
*
* @param {number} distance
* @param {Vector2} minTarget
* @param {Vector2} maxTarget
*/
getViewBounds( distance, minTarget, maxTarget ) {
_v3$1.set( - 1, - 1,
0.5 ).applyMatrix4( this.projectionMatrixInverse );
/**
* Computes the width and height of the camera's viewable rectangle at a
given distance along the viewing direction.
*
* @param {number} distance
* @param {Vector2} target - Vector2 target used to store result where x is
width and y is height.
* @returns {Vector2}
*/
getViewSize( distance, target ) {
/**
* Sets an offset in a larger frustum. This is useful for multi-window or
* multi-monitor/multi-machine setups.
*
* For example, if you have 3x2 monitors and each monitor is 1920x1080 and
* the monitors are in grid like this
*
* +---+---+---+
* | A | B | C |
* +---+---+---+
* | D | E | F |
* +---+---+---+
*
* then for each monitor you would call it like this
*
* const w = 1920;
* const h = 1080;
* const fullWidth = w * 3;
* const fullHeight = h * 2;
*
* --A--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
* --B--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
* --C--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
* --D--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
* --E--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
* --F--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
*
* Note there is no reason monitors have to be the same size or in a grid.
*
* @param {number} fullWidth
* @param {number} fullHeight
* @param {number} x
* @param {number} y
* @param {number} width
* @param {number} height
*/
setViewOffset( fullWidth, fullHeight, x, y, width, height ) {
this.view = {
enabled: true,
fullWidth: 1,
fullHeight: 1,
offsetX: 0,
offsetY: 0,
width: 1,
height: 1
};
this.view.enabled = true;
this.view.fullWidth = fullWidth;
this.view.fullHeight = fullHeight;
this.view.offsetX = x;
this.view.offsetY = y;
this.view.width = width;
this.view.height = height;
this.updateProjectionMatrix();
clearViewOffset() {
this.view.enabled = false;
this.updateProjectionMatrix();
updateProjectionMatrix() {
toJSON( meta ) {
data.object.fov = this.fov;
data.object.zoom = this.zoom;
data.object.near = this.near;
data.object.far = this.far;
data.object.focus = this.focus;
data.object.aspect = this.aspect;
data.object.filmGauge = this.filmGauge;
data.object.filmOffset = this.filmOffset;
return data;
super();
this.type = 'CubeCamera';
this.renderTarget = renderTarget;
this.coordinateSystem = null;
this.activeMipmapLevel = 0;
}
updateCoordinateSystem() {
cameraPX.up.set( 0, 1, 0 );
cameraPX.lookAt( 1, 0, 0 );
cameraNX.up.set( 0, 1, 0 );
cameraNX.lookAt( - 1, 0, 0 );
cameraPY.up.set( 0, 0, - 1 );
cameraPY.lookAt( 0, 1, 0 );
cameraNY.up.set( 0, 0, 1 );
cameraNY.lookAt( 0, - 1, 0 );
cameraPZ.up.set( 0, 1, 0 );
cameraPZ.lookAt( 0, 0, 1 );
cameraNZ.up.set( 0, 1, 0 );
cameraNZ.lookAt( 0, 0, - 1 );
cameraPX.up.set( 0, - 1, 0 );
cameraPX.lookAt( - 1, 0, 0 );
cameraNX.up.set( 0, - 1, 0 );
cameraNX.lookAt( 1, 0, 0 );
cameraPY.up.set( 0, 0, 1 );
cameraPY.lookAt( 0, 1, 0 );
cameraNY.up.set( 0, 0, - 1 );
cameraNY.lookAt( 0, - 1, 0 );
cameraPZ.up.set( 0, - 1, 0 );
cameraPZ.lookAt( 0, 0, 1 );
cameraNZ.up.set( 0, - 1, 0 );
cameraNZ.lookAt( 0, 0, - 1 );
} else {
}
for ( const camera of cameras ) {
this.add( camera );
camera.updateMatrixWorld();
this.coordinateSystem = renderer.coordinateSystem;
this.updateCoordinateSystem();
renderer.xr.enabled = false;
renderTarget.texture.generateMipmaps = false;
renderTarget.texture.generateMipmaps = generateMipmaps;
renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );
renderer.render( scene, cameraNZ );
renderer.xr.enabled = currentXrEnabled;
renderTarget.texture.needsPMREMUpdate = true;
this.isCubeTexture = true;
this.flipY = false;
get images() {
return this.image;
this.image = value;
this.isWebGLCubeRenderTarget = true;
this.texture.isRenderTargetTexture = true;
this.texture.type = texture.type;
this.texture.colorSpace = texture.colorSpace;
this.texture.generateMipmaps = texture.generateMipmaps;
this.texture.minFilter = texture.minFilter;
this.texture.magFilter = texture.magFilter;
const shader = {
uniforms: {
tEquirect: { value: null },
},
void main() {
#include <begin_vertex>
#include <project_vertex>
}
`,
#include <common>
void main() {
}
`
};
name: 'CubemapFromEquirect',
} );
material.uniforms.tEquirect.value = texture;
texture.minFilter = currentMinFilter;
mesh.geometry.dispose();
mesh.material.dispose();
return this;
renderer.setRenderTarget( this, i );
renderer.setRenderTarget( currentRenderTarget );
class FogExp2 {
this.isFogExp2 = true;
this.name = '';
clone() {
toJSON( /* meta */ ) {
return {
type: 'FogExp2',
name: this.name,
color: this.color.getHex(),
density: this.density
};
class Fog {
this.isFog = true;
this.name = '';
clone() {
toJSON( /* meta */ ) {
return {
type: 'Fog',
name: this.name,
color: this.color.getHex(),
near: this.near,
far: this.far
};
constructor() {
super();
this.isScene = true;
this.type = 'Scene';
this.background = null;
this.environment = null;
this.fog = null;
this.backgroundBlurriness = 0;
this.backgroundIntensity = 1;
this.backgroundRotation = new Euler();
this.environmentIntensity = 1;
this.environmentRotation = new Euler();
this.overrideMaterial = null;
this.backgroundBlurriness = source.backgroundBlurriness;
this.backgroundIntensity = source.backgroundIntensity;
this.backgroundRotation.copy( source.backgroundRotation );
this.environmentIntensity = source.environmentIntensity;
this.environmentRotation.copy( source.environmentRotation );
this.matrixAutoUpdate = source.matrixAutoUpdate;
return this;
toJSON( meta ) {
return data;
class InterleavedBuffer {
this.isInterleavedBuffer = true;
this.array = array;
this.stride = stride;
this.count = array !== undefined ? array.length / stride : 0;
this.usage = StaticDrawUsage;
this.updateRanges = [];
this.version = 0;
this.uuid = generateUUID();
onUploadCallback() {}
setUsage( value ) {
this.usage = value;
return this;
clearUpdateRanges() {
this.updateRanges.length = 0;
copy( source ) {
return this;
index1 *= this.stride;
index2 *= attribute.stride;
return this;
}
set( value, offset = 0 ) {
return this;
clone( data ) {
data.arrayBuffers = {};
this.array.buffer._uuid = generateUUID();
data.arrayBuffers[ this.array.buffer._uuid ] =
this.array.slice( 0 ).buffer;
return ib;
onUpload( callback ) {
this.onUploadCallback = callback;
return this;
toJSON( data ) {
data.arrayBuffers = {};
//
return {
uuid: this.uuid,
buffer: this.array.buffer._uuid,
type: this.array.constructor.name,
stride: this.stride
};
class InterleavedBufferAttribute {
this.isInterleavedBufferAttribute = true;
this.name = '';
this.data = interleavedBuffer;
this.itemSize = itemSize;
this.offset = offset;
this.normalized = normalized;
get count() {
return this.data.count;
get array() {
return this.data.array;
this.data.needsUpdate = value;
}
applyMatrix4( m ) {
_vector$7.fromBufferAttribute( this, i );
_vector$7.applyMatrix4( m );
return this;
applyNormalMatrix( m ) {
_vector$7.fromBufferAttribute( this, i );
_vector$7.applyNormalMatrix( m );
return this;
transformDirection( m ) {
_vector$7.fromBufferAttribute( this, i );
_vector$7.transformDirection( m );
return this;
return value;
}
return this;
setX( index, x ) {
return this;
setY( index, y ) {
return this;
setZ( index, z ) {
return this;
setW( index, w ) {
return this;
getX( index ) {
getY( index ) {
return y;
getZ( index ) {
return z;
getW( index ) {
return w;
setXY( index, x, y ) {
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
this.data.array[ index + 0 ] = x;
this.data.array[ index + 1 ] = y;
return this;
setXYZ( index, x, y, z ) {
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
this.data.array[ index + 0 ] = x;
this.data.array[ index + 1 ] = y;
this.data.array[ index + 2 ] = z;
return this;
setXYZW( index, x, y, z, w ) {
if ( this.normalized ) {
x = normalize( x, this.array );
y = normalize( y, this.array );
z = normalize( z, this.array );
w = normalize( w, this.array );
this.data.array[ index + 0 ] = x;
this.data.array[ index + 1 ] = y;
this.data.array[ index + 2 ] = z;
this.data.array[ index + 3 ] = w;
return this;
clone( data ) {
data.interleavedBuffers = {};
data.interleavedBuffers[ this.data.uuid ] =
this.data.clone( data );
return new
InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ],
this.itemSize, this.offset, this.normalized );
toJSON( data ) {
console.log( 'THREE.InterleavedBufferAttribute.toJSON():
Serializing an interleaved buffer attribute will de-interleave buffer data.' );
return {
itemSize: this.itemSize,
type: this.array.constructor.name,
array: array,
normalized: this.normalized
};
} else {
data.interleavedBuffers[ this.data.uuid ] =
this.data.toJSON( data );
return {
isInterleavedBufferAttribute: true,
itemSize: this.itemSize,
data: this.data.uuid,
offset: this.offset,
normalized: this.normalized
};
constructor( parameters ) {
super();
this.isSpriteMaterial = true;
this.type = 'SpriteMaterial';
this.map = null;
this.alphaMap = null;
this.rotation = 0;
this.sizeAttenuation = true;
this.transparent = true;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.rotation = source.rotation;
this.sizeAttenuation = source.sizeAttenuation;
this.fog = source.fog;
return this;
let _geometry;
super();
this.isSprite = true;
this.type = 'Sprite';
this.geometry = _geometry;
this.material = material;
_worldScale.setFromMatrixScale( this.matrixWorld );
_viewWorldMatrix.copy( raycaster.camera.matrixWorld );
this.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse,
this.matrixWorld );
_mvPosition.setFromMatrixPosition( this.modelViewMatrix );
if ( raycaster.camera.isPerspectiveCamera &&
this.material.sizeAttenuation === false ) {
_worldScale.multiplyScalar( - _mvPosition.z );
if ( rotation !== 0 ) {
return;
intersects.push( {
distance: distance,
point: _intersectPoint.clone(),
uv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC,
_uvA, _uvB, _uvC, new Vector2() ),
face: null,
object: this
} );
this.material = source.material;
return this;
} else {
_rotatedPosition.copy( _alignedPosition );
vertexPosition.copy( mvPosition );
vertexPosition.x += _rotatedPosition.x;
vertexPosition.y += _rotatedPosition.y;
constructor() {
super();
this._currentLevel = 0;
this.type = 'LOD';
Object.defineProperties( this, {
levels: {
enumerable: true,
value: []
},
isLOD: {
value: true,
}
} );
this.autoUpdate = true;
copy( source ) {
this.autoUpdate = source.autoUpdate;
return this;
let l;
break;
this.add( object );
return this;
removeLevel( distance ) {
return true;
}
return false;
getCurrentLevel() {
return this._currentLevel;
getObjectForDistance( distance ) {
if ( levels.length > 0 ) {
let i, l;
if ( levels[ i ].object.visible ) {
levelDistance -= levelDistance *
levels[ i ].hysteresis;
break;
return null;
if ( levels.length > 0 ) {
_v1$2.setFromMatrixPosition( this.matrixWorld );
update( camera ) {
if ( levels.length > 1 ) {
_v1$2.setFromMatrixPosition( camera.matrixWorld );
_v2$1.setFromMatrixPosition( this.matrixWorld );
let i, l;
if ( levels[ i ].object.visible ) {
levelDistance -= levelDistance *
levels[ i ].hysteresis;
} else {
break;
this._currentLevel = i - 1;
for ( ; i < l; i ++ ) {
toJSON( meta ) {
const data = super.toJSON( meta );
data.object.levels = [];
data.object.levels.push( {
object: level.object.uuid,
distance: level.distance,
hysteresis: level.hysteresis
} );
return data;
this.isSkinnedMesh = true;
this.type = 'SkinnedMesh';
this.bindMode = AttachedBindMode;
this.bindMatrix = new Matrix4();
this.bindMatrixInverse = new Matrix4();
this.boundingBox = null;
this.boundingSphere = null;
computeBoundingBox() {
const geometry = this.geometry;
this.boundingBox.makeEmpty();
this.getVertexPosition( i, _vertex );
this.boundingBox.expandByPoint( _vertex );
computeBoundingSphere() {
this.boundingSphere.makeEmpty();
this.getVertexPosition( i, _vertex );
this.boundingSphere.expandByPoint( _vertex );
this.bindMode = source.bindMode;
this.bindMatrix.copy( source.bindMatrix );
this.bindMatrixInverse.copy( source.bindMatrixInverse );
this.skeleton = source.skeleton;
_sphere$5.copy( this.boundingSphere );
_sphere$5.applyMatrix4( matrixWorld );
return target;
this.skeleton = skeleton;
this.updateMatrixWorld( true );
this.skeleton.calculateInverses();
bindMatrix = this.matrixWorld;
this.bindMatrix.copy( bindMatrix );
this.bindMatrixInverse.copy( bindMatrix ).invert();
pose() {
this.skeleton.pose();
normalizeSkinWeights() {
vector.fromBufferAttribute( skinWeight, i );
vector.multiplyScalar( scale );
} else {
updateMatrixWorld( force ) {
super.updateMatrixWorld( force );
} else {
vector.set( 0, 0, 0 );
if ( weight !== 0 ) {
constructor() {
super();
this.isBone = true;
this.type = 'Bone';
}
class DataTexture extends Texture {
this.isDataTexture = true;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
class Skeleton {
this.uuid = generateUUID();
this.bones = bones.slice( 0 );
this.boneInverses = boneInverses;
this.boneMatrices = null;
this.boneTexture = null;
this.init();
init() {
if ( boneInverses.length === 0 ) {
this.calculateInverses();
} else {
this.boneInverses = [];
calculateInverses() {
this.boneInverses.length = 0;
if ( this.bones[ i ] ) {
this.boneInverses.push( inverse );
pose() {
if ( bone ) {
} else {
bone.matrix.copy( bone.matrixWorld );
update() {
boneTexture.needsUpdate = true;
clone() {
computeBoneTexture() {
// layout (1 matrix = 4 pixels)
// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)
// with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)
// 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)
// 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)
// 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)
this.boneMatrices = boneMatrices;
this.boneTexture = boneTexture;
return this;
getBoneByName( name ) {
return bone;
return undefined;
dispose( ) {
this.boneTexture.dispose();
this.boneTexture = null;
this.bones.push( bone );
this.boneInverses.push( new
Matrix4().fromArray( json.boneInverses[ i ] ) );
this.init();
return this;
toJSON() {
const data = {
metadata: {
version: 4.6,
type: 'Skeleton',
generator: 'Skeleton.toJSON'
},
bones: [],
boneInverses: []
};
data.uuid = this.uuid;
return data;
}
}
this.isInstancedBufferAttribute = true;
this.meshPerAttribute = meshPerAttribute;
copy( source ) {
super.copy( source );
this.meshPerAttribute = source.meshPerAttribute;
return this;
toJSON() {
data.meshPerAttribute = this.meshPerAttribute;
data.isInstancedBufferAttribute = true;
return data;
this.isInstancedMesh = true;
this.count = count;
this.boundingBox = null;
this.boundingSphere = null;
this.setMatrixAt( i, _identity );
computeBoundingBox() {
geometry.computeBoundingBox();
this.boundingBox.makeEmpty();
this.getMatrixAt( i, _instanceLocalMatrix );
this.boundingBox.union( _box3 );
computeBoundingSphere() {
this.boundingSphere.makeEmpty();
this.getMatrixAt( i, _instanceLocalMatrix );
this.boundingSphere.union( _sphere$4 );
this.instanceMatrix.copy( source.instanceMatrix );
this.count = source.count;
return this;
_mesh$1.geometry = this.geometry;
_mesh$1.material = this.material;
_sphere$4.copy( this.boundingSphere );
_sphere$4.applyMatrix4( matrixWorld );
_instanceWorldMatrix.multiplyMatrices( matrixWorld,
_instanceLocalMatrix );
_mesh$1.matrixWorld = _instanceWorldMatrix;
_instanceIntersects.length = 0;
let morphInfluencesSum = 0;
morphInfluencesSum += objectInfluences[ i ];
updateMorphTargets() {
dispose() {
this.morphTexture.dispose();
this.morphTexture = null;
return this;
class Plane {
this.isPlane = true;
this.normal = normal;
this.constant = constant;
this.normal.copy( normal );
this.constant = constant;
return this;
setComponents( x, y, z, w ) {
this.normal.set( x, y, z );
this.constant = w;
return this;
}
this.normal.copy( normal );
this.constant = - point.dot( this.normal );
return this;
setFromCoplanarPoints( a, b, c ) {
this.setFromNormalAndCoplanarPoint( normal, a );
return this;
copy( plane ) {
this.normal.copy( plane.normal );
this.constant = plane.constant;
return this;
normalize() {
return this;
negate() {
this.constant *= - 1;
this.normal.negate();
return this;
distanceToPoint( point ) {
distanceToSphere( sphere ) {
if ( denominator === 0 ) {
if ( t < 0 || t > 1 ) {
return null;
intersectsLine( line ) {
// Note: this tests if a line intersects the plane, not whether it (or
its end-points) are coplanar with it.
return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign >
0 );
}
intersectsBox( box ) {
intersectsSphere( sphere ) {
coplanarPoint( target ) {
const referencePoint =
this.coplanarPoint( _vector1 ).applyMatrix4( matrix );
return this;
translate( offset ) {
return this;
equals( plane ) {
clone() {
}
const _sphere$3 = /*@__PURE__*/ new Sphere();
const _vector$6 = /*@__PURE__*/ new Vector3();
class Frustum {
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;
copy( frustum ) {
return this;
} else {
return this;
intersectsObject( object ) {
} else {
intersectsSprite( sprite ) {
_sphere$3.center.set( 0, 0, 0 );
_sphere$3.radius = 0.7071067811865476;
_sphere$3.applyMatrix4( sprite.matrixWorld );
}
intersectsSphere( sphere ) {
return false;
return true;
intersectsBox( box ) {
return false;
return true;
containsPoint( point ) {
return false;
}
}
return true;
clone() {
function ascIdSort( a, b ) {
return a - b;
function sortOpaque( a, b ) {
function sortTransparent( a, b ) {
class MultiDrawRenderList {
constructor() {
this.index = 0;
this.pool = [];
this.list = [];
pool.push( {
start: - 1,
count: - 1,
z: - 1,
index: - 1,
} );
}
const item = pool[ this.index ];
list.push( item );
this.index ++;
item.start = start;
item.count = count;
item.z = z;
item.index = index;
reset() {
this.list.length = 0;
this.index = 0;
// use the component getters and setters if the array data cannot
// be copied directly
const vertexCount = src.count;
for ( let i = 0; i < vertexCount; i ++ ) {
} else {
target.needsUpdate = true;
target[ i ] = src[ i ];
} else {
// if the arrays use the same data layout we can use a fast block copy
const len = Math.min( src.length, target.length );
target.set( new src.constructor( src.buffer, 0, len ) );
get maxInstanceCount() {
return this._maxInstanceCount;
get instanceCount() {
get unusedVertexCount() {
get unusedIndexCount() {
this.isBatchedMesh = true;
this.perObjectFrustumCulled = true;
this.sortObjects = true;
this.boundingBox = null;
this.boundingSphere = null;
this.customSort = null;
// instance, geometry ids that have been set as inactive, and are
available to be overwritten
this._availableInstanceIds = [];
this._availableGeometryIds = [];
// flags
this._visibilityChanged = true;
this._geometryInitialized = false;
this._initMatricesTexture();
this._initIndirectTexture();
_initMatricesTexture() {
this._matricesTexture = matricesTexture;
_initIndirectTexture() {
this._indirectTexture = indirectTexture;
_initColorsTexture() {
this._colorsTexture = colorsTexture;
_initializeGeometry( reference ) {
const srcAttribute =
reference.getAttribute( attributeName );
const { array, itemSize, normalized } = srcAttribute;
this._geometryInitialized = true;
// Make sure the geometry is compatible with the existing combined geometry
attributes
_validateGeometry( geometry ) {
if ( ! geometry.hasAttribute( attributeName ) ) {
}
validateInstanceId( instanceId ) {
validateGeometryId( geometryId ) {
setCustomSort( func ) {
this.customSort = func;
return this;
computeBoundingBox() {
boundingBox.makeEmpty();
for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) {
}
}
computeBoundingSphere() {
boundingSphere.makeEmpty();
for ( let i = 0, l = instanceInfo.length; i < l; i ++ ) {
addInstance( geometryId ) {
const instanceInfo = {
visible: true,
active: true,
geometryIndex: geometryId,
};
this._availableInstanceIds.sort( ascIdSort );
drawId = this._availableInstanceIds.shift();
this._instanceInfo[ drawId ] = instanceInfo;
} else {
drawId = this._instanceInfo.length;
this._instanceInfo.push( instanceInfo );
this._visibilityChanged = true;
return drawId;
this._initializeGeometry( geometry );
this._validateGeometry( geometry );
const geometryInfo = {
// geometry information
vertexStart: - 1,
vertexCount: - 1,
reservedVertexCount: - 1,
indexStart: - 1,
indexCount: - 1,
reservedIndexCount: - 1,
// state
boundingBox: null,
boundingSphere: null,
active: true,
};
geometryInfo.indexStart = this._nextIndexStart;
geometryInfo.reservedIndexCount = reservedIndexCount === - 1 ?
index.count : reservedIndexCount;
if (
geometryInfo.indexStart !== - 1 &&
geometryInfo.indexStart + geometryInfo.reservedIndexCount >
this._maxIndexCount ||
geometryInfo.vertexStart + geometryInfo.reservedVertexCount >
this._maxVertexCount
) {
// update id
let geometryId;
if ( this._availableGeometryIds.length > 0 ) {
this._availableGeometryIds.sort( ascIdSort );
geometryId = this._availableGeometryIds.shift();
geometryInfoList[ geometryId ] = geometryInfo;
} else {
geometryId = this._geometryCount;
this._geometryCount ++;
geometryInfoList.push( geometryInfo );
return geometryId;
this._validateGeometry( geometry );
const batchGeometry = this.geometry;
const hasIndex = batchGeometry.getIndex() !== null;
const dstIndex = batchGeometry.getIndex();
const srcIndex = geometry.getIndex();
const geometryInfo = this._geometryInfo[ geometryId ];
if (
hasIndex &&
srcIndex.count > geometryInfo.reservedIndexCount ||
geometry.attributes.position.count >
geometryInfo.reservedVertexCount
) {
dstAttribute.setComponent( index, c, 0 );
dstAttribute.needsUpdate = true;
dstAttribute.addUpdateRange( vertexStart * itemSize,
reservedVertexCount * itemSize );
// copy index
if ( hasIndex ) {
dstIndex.needsUpdate = true;
dstIndex.addUpdateRange( indexStart,
geometryInfo.reservedIndexCount );
geometryInfo.boundingBox = geometry.boundingBox.clone();
geometryInfo.boundingSphere = null;
if ( geometry.boundingSphere !== null ) {
geometryInfo.boundingSphere = geometry.boundingSphere.clone();
this._visibilityChanged = true;
return geometryId;
deleteGeometry( geometryId ) {
return this;
this.deleteInstance( i );
return this;
deleteInstance( instanceId ) {
this.validateInstanceId( instanceId );
return this;
optimize() {
} );
continue;
}
geometryInfo.indexStart = nextIndexStart;
nextIndexStart += geometryInfo.reservedIndexCount;
geometryInfo.vertexStart = nextVertexStart;
nextVertexStart += geometryInfo.reservedVertexCount;
geometryInfo.start = geometry.index ? geometryInfo.indexStart :
geometryInfo.vertexStart;
return this;
return null;
let iv = i;
if ( index ) {
iv = index.getX( iv );
geometryInfo.boundingBox = box;
target.copy( geometryInfo.boundingBox );
return target;
return null;
let maxRadiusSq = 0;
for ( let i = geometryInfo.start, l = geometryInfo.start +
geometryInfo.count; i < l; i ++ ) {
let iv = i;
if ( index ) {
iv = index.getX( iv );
_vector$5.fromBufferAttribute( position, iv );
maxRadiusSq = Math.max( maxRadiusSq,
sphere.center.distanceToSquared( _vector$5 ) );
target.copy( geometryInfo.boundingSphere );
return target;
this.validateInstanceId( instanceId );
return this;
this.validateInstanceId( instanceId );
this._initColorsTexture();
return this;
this.validateInstanceId( instanceId );
return color.fromArray( this._colorsTexture.image.data, instanceId *
4 );
this.validateInstanceId( instanceId );
return this;
return this;
getVisibleAt( instanceId ) {
this.validateInstanceId( instanceId );
return this;
getGeometryIdAt( instanceId ) {
this.validateInstanceId( instanceId );
this.validateGeometryId( geometryId );
target.indexStart = geometryInfo.indexStart;
target.indexCount = geometryInfo.indexCount;
target.reservedIndexCount = geometryInfo.reservedIndexCount;
target.start = geometryInfo.start;
target.count = geometryInfo.count;
return target;
setInstanceCount( maxInstanceCount ) {
instanceInfo.pop();
availableInstanceIds.pop();
}
// copy the multi draw counts
const multiDrawCounts = new Int32Array( maxInstanceCount );
const multiDrawStarts = new Int32Array( maxInstanceCount );
copyArrayContents( this._multiDrawCounts, multiDrawCounts );
copyArrayContents( this._multiDrawStarts, multiDrawStarts );
this._multiDrawCounts = multiDrawCounts;
this._multiDrawStarts = multiDrawStarts;
this._maxInstanceCount = maxInstanceCount;
indirectTexture.dispose();
this._initIndirectTexture();
copyArrayContents( indirectTexture.image.data,
this._indirectTexture.image.data );
matricesTexture.dispose();
this._initMatricesTexture();
copyArrayContents( matricesTexture.image.data,
this._matricesTexture.image.data );
if ( colorsTexture ) {
colorsTexture.dispose();
this._initColorsTexture();
copyArrayContents( colorsTexture.image.data,
this._colorsTexture.image.data );
//
if ( this._geometryInitialized ) {
this._geometryInitialized = false;
this.geometry = new BufferGeometry();
this._initializeGeometry( oldGeometry );
copyArrayContents( oldGeometry.index.array,
geometry.index.array );
continue;
_batchIntersects.length = 0;
_mesh.material = null;
_mesh.geometry.index = null;
_mesh.geometry.attributes = {};
_mesh.geometry.setDrawRange( 0, Infinity );
copy( source ) {
super.copy( source );
this.geometry = source.geometry.clone();
this.perObjectFrustumCulled = source.perObjectFrustumCulled;
this.sortObjects = source.sortObjects;
this.boundingBox = source.boundingBox !== null ?
source.boundingBox.clone() : null;
this.boundingSphere = source.boundingSphere !== null ?
source.boundingSphere.clone() : null;
this._geometryInfo = source._geometryInfo.map( info => ( {
...info,
this._maxInstanceCount = source._maxInstanceCount;
this._maxVertexCount = source._maxVertexCount;
this._maxIndexCount = source._maxIndexCount;
this._geometryInitialized = source._geometryInitialized;
this._geometryCount = source._geometryCount;
this._multiDrawCounts = source._multiDrawCounts.slice();
this._multiDrawStarts = source._multiDrawStarts.slice();
this._matricesTexture = source._matricesTexture.clone();
this._matricesTexture.image.data =
this._matricesTexture.image.data.slice();
this._colorsTexture = source._colorsTexture.clone();
this._colorsTexture.image.data =
this._colorsTexture.image.data.slice();
return this;
dispose() {
this._matricesTexture.dispose();
this._matricesTexture = null;
this._indirectTexture.dispose();
this._indirectTexture = null;
this._colorsTexture.dispose();
this._colorsTexture = null;
return this;
}
onBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {
// if visibility has not changed and frustum culling and object sorting
is not required
// then skip iterating over all items
if ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && !
this.sortObjects ) {
return;
_matrix$1
.multiplyMatrices( camera.projectionMatrix,
camera.matrixWorldInverse )
.multiply( this.matrixWorld );
_frustum.setFromProjectionMatrix(
_matrix$1,
renderer.coordinateSystem
);
let multiDrawCount = 0;
if ( this.sortObjects ) {
if ( ! culled ) {
} else {
_renderList.reset();
} else {
if ( ! culled ) {
const geometryInfo =
geometryInfoList[ geometryId ];
multiDrawStarts[ multiDrawCount ] =
geometryInfo.start * bytesPerElement;
multiDrawCounts[ multiDrawCount ] =
geometryInfo.count;
indirectArray[ multiDrawCount ] = i;
multiDrawCount ++;
indirectTexture.needsUpdate = true;
this._multiDrawCount = multiDrawCount;
this._visibilityChanged = false;
super();
this.isLineBasicMaterial = true;
this.type = 'LineBasicMaterial';
this.map = null;
this.linewidth = 1;
this.linecap = 'round';
this.linejoin = 'round';
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.linewidth = source.linewidth;
this.linecap = source.linecap;
this.linejoin = source.linejoin;
this.fog = source.fog;
return this;
this.isLine = true;
this.type = 'Line';
this.geometry = geometry;
this.material = material;
this.updateMorphTargets();
return this;
computeLineDistances() {
_vStart.fromBufferAttribute( positionAttribute, i - 1 );
_vEnd.fromBufferAttribute( positionAttribute, i );
lineDistances[ i ] = lineDistances[ i - 1 ];
lineDistances[ i ] += _vStart.distanceTo( _vEnd );
} else {
return this;
}
raycast( raycaster, intersects ) {
_sphere$1.copy( geometry.boundingSphere );
_sphere$1.applyMatrix4( matrixWorld );
_sphere$1.radius += threshold;
//
const a = index.getX( i );
const b = index.getX( i + 1 );
if ( intersect ) {
intersects.push( intersect );
if ( this.isLineLoop ) {
if ( intersect ) {
intersects.push( intersect );
} else {
if ( intersect ) {
intersects.push( intersect );
if ( this.isLineLoop ) {
if ( intersect ) {
intersects.push( intersect );
updateMorphTargets() {
if ( keys.length > 0 ) {
this.morphTargetInfluences = [];
this.morphTargetDictionary = {};
this.morphTargetInfluences.push( 0 );
this.morphTargetDictionary[ name ] = m;
_vStart.fromBufferAttribute( positionAttribute, a );
_vEnd.fromBufferAttribute( positionAttribute, b );
return {
distance: distance,
// What do we want? intersection point on the ray or on the segment??
// point: raycaster.ray.at( distance ),
point:
_intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ),
index: a,
face: null,
faceIndex: null,
barycoord: null,
object: object
};
}
const _start = /*@__PURE__*/ new Vector3();
const _end = /*@__PURE__*/ new Vector3();
this.isLineSegments = true;
this.type = 'LineSegments';
computeLineDistances() {
_start.fromBufferAttribute( positionAttribute, i );
_end.fromBufferAttribute( positionAttribute, i + 1 );
} else {
console.warn( 'THREE.LineSegments.computeLineDistances():
Computation only possible with non-indexed BufferGeometry.' );
return this;
this.isLineLoop = true;
this.type = 'LineLoop';
constructor( parameters ) {
super();
this.isPointsMaterial = true;
this.type = 'PointsMaterial';
this.map = null;
this.alphaMap = null;
this.size = 1;
this.sizeAttenuation = true;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.size = source.size;
this.sizeAttenuation = source.sizeAttenuation;
this.fog = source.fog;
return this;
super();
this.isPoints = true;
this.type = 'Points';
this.geometry = geometry;
this.material = material;
this.updateMorphTargets();
return this;
_sphere.copy( geometry.boundingSphere );
_sphere.applyMatrix4( matrixWorld );
_sphere.radius += threshold;
//
const a = index.getX( i );
_position$2.fromBufferAttribute( positionAttribute, a );
} else {
_position$2.fromBufferAttribute( positionAttribute, i );
updateMorphTargets() {
if ( keys.length > 0 ) {
this.morphTargetInfluences = [];
this.morphTargetDictionary = {};
this.morphTargetInfluences.push( 0 );
this.morphTargetDictionary[ name ] = m;
intersects.push( {
distance: distance,
distanceToRay: Math.sqrt( rayPointDistanceSq ),
point: intersectPoint,
index: index,
face: null,
faceIndex: null,
barycoord: null,
object: object
} );
constructor() {
super();
this.isGroup = true;
this.type = 'Group';
}
}
this.isVideoTexture = true;
this.generateMipmaps = false;
function updateVideo() {
scope.needsUpdate = true;
video.requestVideoFrameCallback( updateVideo );
if ( 'requestVideoFrameCallback' in video ) {
video.requestVideoFrameCallback( updateVideo );
clone() {
update() {
this.needsUpdate = true;
update() {
clone() {
setFrame( frame ) {
this.image = frame;
this.needsUpdate = true;
this.isFramebufferTexture = true;
this.magFilter = NearestFilter;
this.minFilter = NearestFilter;
this.generateMipmaps = false;
this.needsUpdate = true;
this.isCompressedTexture = true;
this.image = { width: width, height: height };
this.mipmaps = mipmaps;
this.flipY = false;
this.generateMipmaps = false;
this.isCompressedArrayTexture = true;
this.image.depth = depth;
this.wrapR = ClampToEdgeWrapping;
addLayerUpdate( layerIndex ) {
this.layerUpdates.add( layerIndex );
clearLayerUpdates() {
this.layerUpdates.clear();
this.isCompressedCubeTexture = true;
this.isCubeTexture = true;
this.image = images;
}
}
this.isCanvasTexture = true;
this.needsUpdate = true;
this.isDepthTexture = true;
this.flipY = false;
this.generateMipmaps = false;
this.compareFunction = null;
copy( source ) {
super.copy( source );
this.compareFunction = source.compareFunction;
return this;
toJSON( meta ) {
return data;
/**
* Extensible curve object.
*
* Some common of curve methods:
* .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )
* .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )
* .getPoints(), .getSpacedPoints()
* .getLength()
* .updateArcLengths()
*
* This following curves inherit from THREE.Curve:
*
* -- 2D curves --
* THREE.ArcCurve
* THREE.CubicBezierCurve
* THREE.EllipseCurve
* THREE.LineCurve
* THREE.QuadraticBezierCurve
* THREE.SplineCurve
*
* -- 3D curves --
* THREE.CatmullRomCurve3
* THREE.CubicBezierCurve3
* THREE.LineCurve3
* THREE.QuadraticBezierCurve3
*
* A series of curves can be represented as a THREE.CurvePath.
*
**/
class Curve {
constructor() {
this.type = 'Curve';
this.arcLengthDivisions = 200;
getPoint( /* t, optionalTarget */ ) {
getPointAt( u, optionalTarget ) {
const t = this.getUtoTmapping( u );
return this.getPoint( t, optionalTarget );
getPoints( divisions = 5 ) {
return points;
getSpacedPoints( divisions = 5 ) {
return points;
getLength() {
}
// Get list of cumulative segment lengths
if ( this.cacheArcLengths &&
( this.cacheArcLengths.length === divisions + 1 ) &&
! this.needsUpdate ) {
return this.cacheArcLengths;
this.needsUpdate = false;
cache.push( 0 );
this.cacheArcLengths = cache;
return cache; // { sums: cache, sum: sum }; Sum is in the last element.
updateArcLengths() {
this.needsUpdate = true;
this.getLengths();
getUtoTmapping( u, distance ) {
let i = 0;
const il = arcLengths.length;
if ( distance ) {
targetArcLength = distance;
} else {
targetArcLength = u * arcLengths[ il - 1 ];
// binary search for the index with largest value smaller than target u
distance
if ( comparison < 0 ) {
low = i + 1;
high = i - 1;
} else {
high = i;
break;
// DONE
i = high;
return i / ( il - 1 );
const t = ( i + segmentFraction ) / ( il - 1 );
return t;
getTangent( t, optionalTarget ) {
if ( t1 < 0 ) t1 = 0;
if ( t2 > 1 ) t2 = 1;
return tangent;
getTangentAt( u, optionalTarget ) {
const t = this.getUtoTmapping( u );
return this.getTangent( t, optionalTarget );
// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf
if ( tx <= min ) {
min = tx;
normal.set( 1, 0, 0 );
if ( ty <= min ) {
min = ty;
normal.set( 0, 1, 0 );
if ( tz <= min ) {
normal.set( 0, 0, 1 );
vec.normalize();
const theta = Math.acos( clamp( tangents[ i -
1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
theta = - theta;
// twist a little...
return {
tangents: tangents,
normals: normals,
binormals: binormals
};
clone() {
copy( source ) {
this.arcLengthDivisions = source.arcLengthDivisions;
return this;
}
toJSON() {
const data = {
metadata: {
version: 4.6,
type: 'Curve',
generator: 'Curve.toJSON'
}
};
data.arcLengthDivisions = this.arcLengthDivisions;
data.type = this.type;
return data;
fromJSON( json ) {
this.arcLengthDivisions = json.arcLengthDivisions;
return this;
super();
this.isEllipseCurve = true;
this.type = 'EllipseCurve';
this.aX = aX;
this.aY = aY;
this.xRadius = xRadius;
this.yRadius = yRadius;
this.aStartAngle = aStartAngle;
this.aEndAngle = aEndAngle;
this.aClockwise = aClockwise;
this.aRotation = aRotation;
if ( samePoints ) {
deltaAngle = 0;
} else {
deltaAngle = twoPi;
deltaAngle = - twoPi;
} else {
if ( this.aRotation !== 0 ) {
const tx = x - this.aX;
const ty = y - this.aY;
return point.set( x, y );
}
copy( source ) {
super.copy( source );
this.aX = source.aX;
this.aY = source.aY;
this.xRadius = source.xRadius;
this.yRadius = source.yRadius;
this.aStartAngle = source.aStartAngle;
this.aEndAngle = source.aEndAngle;
this.aClockwise = source.aClockwise;
this.aRotation = source.aRotation;
return this;
toJSON() {
data.aX = this.aX;
data.aY = this.aY;
data.xRadius = this.xRadius;
data.yRadius = this.yRadius;
data.aStartAngle = this.aStartAngle;
data.aEndAngle = this.aEndAngle;
data.aClockwise = this.aClockwise;
data.aRotation = this.aRotation;
return data;
fromJSON( json ) {
super.fromJSON( json );
this.aX = json.aX;
this.aY = json.aY;
this.xRadius = json.xRadius;
this.yRadius = json.yRadius;
this.aStartAngle = json.aStartAngle;
this.aEndAngle = json.aEndAngle;
this.aClockwise = json.aClockwise;
this.aRotation = json.aRotation;
return this;
this.isArcCurve = true;
this.type = 'ArcCurve';
/**
* Centripetal CatmullRom Curve - which is useful for avoiding
* cusps and self-intersections in non-uniform catmull rom curves.
* http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf
*
* curve.type accepts centripetal(default), chordal and catmullrom
* curve.tension is used for catmullrom which defaults to 0.5
*/
/*
Based on an optimized c++ solution in
- http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-
no-self-intersections/
- http://ideone.com/NoEbVM
This CubicPoly class could be used for reusing some variables and calculations,
but for three.js curve use, it could be possible inlined and flatten into a single
function call
which can be placed in CurveUtils.
*/
function CubicPoly() {
let c0 = 0, c1 = 0, c2 = 0, c3 = 0;
/*
* Compute coefficients for a cubic polynomial
* p(s) = c0 + c1*s + c2*s^2 + c3*s^3
* such that
* p(0) = x0, p(1) = x1
* and
* p'(0) = t0, p'(1) = t1.
*/
function init( x0, x1, t0, t1 ) {
c0 = x0;
c1 = t0;
c2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;
c3 = 2 * x0 - 2 * x1 + t0 + t1;
return {
},
},
calc: function ( t ) {
const t2 = t * t;
const t3 = t2 * t;
return c0 + c1 * t + c2 * t2 + c3 * t3;
};
//
super();
this.isCatmullRomCurve3 = true;
this.type = 'CatmullRomCurve3';
this.points = points;
this.closed = closed;
this.curveType = curveType;
this.tension = tension;
const p = ( l - ( this.closed ? 0 : 1 ) ) * t;
let intPoint = Math.floor( p );
let weight = p - intPoint;
if ( this.closed ) {
intPoint = l - 2;
weight = 1;
p0 = points[ ( intPoint - 1 ) % l ];
} else {
p3 = points[ ( intPoint + 2 ) % l ];
} else {
}
if ( this.curveType === 'centripetal' || this.curveType === 'chordal' )
{
point.set(
px.calc( weight ),
py.calc( weight ),
pz.calc( weight )
);
return point;
copy( source ) {
super.copy( source );
this.points = [];
this.points.push( point.clone() );
this.closed = source.closed;
this.curveType = source.curveType;
this.tension = source.tension;
return this;
}
toJSON() {
data.points = [];
data.closed = this.closed;
data.curveType = this.curveType;
data.tension = this.tension;
return data;
fromJSON( json ) {
super.fromJSON( json );
this.points = [];
this.closed = json.closed;
this.curveType = json.curveType;
this.tension = json.tension;
return this;
/**
* Bezier Curves formulas obtained from
* https://en.wikipedia.org/wiki/B%C3%A9zier_curve
*/
const v0 = ( p2 - p0 ) * 0.5;
const v1 = ( p3 - p1 ) * 0.5;
const t2 = t * t;
const t3 = t * t2;
return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1
) * t2 + v0 * t + p1;
}
//
function QuadraticBezierP0( t, p ) {
const k = 1 - t;
return k * k * p;
function QuadraticBezierP1( t, p ) {
return 2 * ( 1 - t ) * t * p;
function QuadraticBezierP2( t, p ) {
return t * t * p;
//
function CubicBezierP0( t, p ) {
const k = 1 - t;
return k * k * k * p;
function CubicBezierP1( t, p ) {
const k = 1 - t;
return 3 * k * k * t * p;
function CubicBezierP2( t, p ) {
return 3 * ( 1 - t ) * t * t * p;
function CubicBezierP3( t, p ) {
return t * t * t * p;
}
function CubicBezier( t, p0, p1, p2, p3 ) {
super();
this.isCubicBezierCurve = true;
this.type = 'CubicBezierCurve';
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
point.set(
CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
CubicBezier( t, v0.y, v1.y, v2.y, v3.y )
);
return point;
copy( source ) {
super.copy( source );
this.v0.copy( source.v0 );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
this.v3.copy( source.v3 );
return this;
toJSON() {
data.v0 = this.v0.toArray();
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
data.v3 = this.v3.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v0.fromArray( json.v0 );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
this.v3.fromArray( json.v3 );
return this;
super();
this.isCubicBezierCurve3 = true;
this.type = 'CubicBezierCurve3';
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
this.v3 = v3;
point.set(
CubicBezier( t, v0.x, v1.x, v2.x, v3.x ),
CubicBezier( t, v0.y, v1.y, v2.y, v3.y ),
CubicBezier( t, v0.z, v1.z, v2.z, v3.z )
);
return point;
copy( source ) {
super.copy( source );
this.v0.copy( source.v0 );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
this.v3.copy( source.v3 );
return this;
toJSON() {
data.v0 = this.v0.toArray();
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
data.v3 = this.v3.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v0.fromArray( json.v0 );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
this.v3.fromArray( json.v3 );
return this;
super();
this.isLineCurve = true;
this.type = 'LineCurve';
this.v1 = v1;
this.v2 = v2;
if ( t === 1 ) {
point.copy( this.v2 );
} else {
return point;
getTangentAt( u, optionalTarget ) {
copy( source ) {
super.copy( source );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
return this;
toJSON() {
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
return this;
super();
this.isLineCurve3 = true;
this.type = 'LineCurve3';
this.v1 = v1;
this.v2 = v2;
if ( t === 1 ) {
point.copy( this.v2 );
} else {
return point;
getTangentAt( u, optionalTarget ) {
copy( source ) {
super.copy( source );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
return this;
toJSON() {
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
return this;
super();
this.isQuadraticBezierCurve = true;
this.type = 'QuadraticBezierCurve';
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
return point;
copy( source ) {
super.copy( source );
this.v0.copy( source.v0 );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
return this;
toJSON() {
data.v0 = this.v0.toArray();
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v0.fromArray( json.v0 );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
return this;
super();
this.isQuadraticBezierCurve3 = true;
this.type = 'QuadraticBezierCurve3';
this.v0 = v0;
this.v1 = v1;
this.v2 = v2;
point.set(
QuadraticBezier( t, v0.x, v1.x, v2.x ),
QuadraticBezier( t, v0.y, v1.y, v2.y ),
QuadraticBezier( t, v0.z, v1.z, v2.z )
);
return point;
copy( source ) {
super.copy( source );
this.v0.copy( source.v0 );
this.v1.copy( source.v1 );
this.v2.copy( source.v2 );
return this;
toJSON() {
data.v0 = this.v0.toArray();
data.v1 = this.v1.toArray();
data.v2 = this.v2.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.v0.fromArray( json.v0 );
this.v1.fromArray( json.v1 );
this.v2.fromArray( json.v2 );
return this;
}
class SplineCurve extends Curve {
constructor( points = [] ) {
super();
this.isSplineCurve = true;
this.type = 'SplineCurve';
this.points = points;
point.set(
CatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),
CatmullRom( weight, p0.y, p1.y, p2.y, p3.y )
);
return point;
copy( source ) {
super.copy( source );
this.points = [];
this.points.push( point.clone() );
return this;
toJSON() {
const data = super.toJSON();
data.points = [];
return data;
fromJSON( json ) {
super.fromJSON( json );
this.points = [];
return this;
/**************************************************************
* Curved Path - a curve path is simply a array of connected
* curves, but retains the api of a curve
**************************************************************/
constructor() {
super();
this.type = 'CurvePath';
this.curves = [];
this.autoClose = false; // Automatically closes the path
add( curve ) {
this.curves.push( curve );
closePath() {
// Add a line curve if start and end of lines are not connected
const startPoint = this.curves[ 0 ].getPoint( 0 );
const endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );
if ( ! startPoint.equals( endPoint ) ) {
return this;
getPoint( t, optionalTarget ) {
const d = t * this.getLength();
const curveLengths = this.getCurveLengths();
let i = 0;
if ( curveLengths[ i ] >= d ) {
i ++;
return null;
getLength() {
this.needsUpdate = true;
this.cacheLengths = null;
this.getCurveLengths();
getCurveLengths() {
// We use cache values if curves and cache array are same length
return this.cacheLengths;
this.cacheLengths = lengths;
return lengths;
getSpacedPoints( divisions = 40 ) {
if ( this.autoClose ) {
points.push( points[ 0 ] );
return points;
getPoints( divisions = 12 ) {
points.push( point );
last = point;
}
}
points.push( points[ 0 ] );
return points;
copy( source ) {
super.copy( source );
this.curves = [];
this.curves.push( curve.clone() );
this.autoClose = source.autoClose;
return this;
toJSON() {
data.autoClose = this.autoClose;
data.curves = [];
return data;
fromJSON( json ) {
super.fromJSON( json );
this.autoClose = json.autoClose;
this.curves = [];
return this;
constructor( points ) {
super();
this.type = 'Path';
if ( points ) {
this.setFromPoints( points );
setFromPoints( points ) {
return this;
moveTo( x, y ) {
return this;
lineTo( x, y ) {
return this;
this.curves.push( curve );
this.currentPoint.set( aX, aY );
return this;
this.curves.push( curve );
this.currentPoint.set( aX, aY );
return this;
return this;
const x0 = this.currentPoint.x;
const y0 = this.currentPoint.y;
return this;
const x0 = this.currentPoint.x;
const y0 = this.currentPoint.y;
return this;
if ( this.curves.length > 0 ) {
if ( ! firstPoint.equals( this.currentPoint ) ) {
this.curves.push( curve );
return this;
copy( source ) {
super.copy( source );
this.currentPoint.copy( source.currentPoint );
return this;
toJSON() {
data.currentPoint = this.currentPoint.toArray();
return data;
fromJSON( json ) {
super.fromJSON( json );
this.currentPoint.fromArray( json.currentPoint );
return this;
super();
this.type = 'LatheGeometry';
this.parameters = {
points: points,
segments: segments,
phiStart: phiStart,
phiLength: phiLength
};
// buffers
// helper variables
const inverseSegments = 1.0 / segments;
const vertex = new Vector3();
const uv = new Vector2();
const normal = new Vector3();
const curNormal = new Vector3();
const prevNormal = new Vector3();
let dx = 0;
let dy = 0;
switch ( j ) {
normal.x = dy * 1.0;
normal.y = - dx;
normal.z = dy * 0.0;
prevNormal.copy( normal );
normal.normalize();
break;
break;
normal.x = dy * 1.0;
normal.y = - dx;
normal.z = dy * 0.0;
curNormal.copy( normal );
normal.x += prevNormal.x;
normal.y += prevNormal.y;
normal.z += prevNormal.z;
normal.normalize();
initNormals.push( normal.x, normal.y, normal.z );
prevNormal.copy( curNormal );
// vertex
// uv
uv.x = i / segments;
uv.y = j / ( points.length - 1 );
// normal
normals.push( x, y, z );
// indices
const a = base;
const b = base + points.length;
const c = base + points.length + 1;
const d = base + 1;
// faces
indices.push( a, b, d );
indices.push( c, d, b );
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
copy( source ) {
super.copy( source );
return this;
this.type = 'CapsuleGeometry';
this.parameters = {
radius: radius,
length: length,
capSegments: capSegments,
radialSegments: radialSegments,
};
}
super();
this.type = 'CircleGeometry';
this.parameters = {
radius: radius,
segments: segments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
// buffers
// helper variables
// center point
vertices.push( 0, 0, 0 );
normals.push( 0, 0, 1 );
uvs.push( 0.5, 0.5 );
// vertex
// normal
normals.push( 0, 0, 1 );
// uvs
// indices
indices.push( i, i + 1, 0 );
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
copy( source ) {
super.copy( source );
return this;
super();
this.type = 'CylinderGeometry';
this.parameters = {
radiusTop: radiusTop,
radiusBottom: radiusBottom,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
// buffers
// helper variables
let index = 0;
const indexArray = [];
const halfHeight = height / 2;
let groupStart = 0;
// generate geometry
generateTorso();
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
function generateTorso() {
let groupCount = 0;
const v = y / heightSegments;
const u = x / radialSegments;
// vertex
// normal
// uv
uvs.push( u, 1 - v );
indexRow.push( index ++ );
indexArray.push( indexRow );
// generate indices
const a = indexArray[ y ][ x ];
const b = indexArray[ y + 1 ][ x ];
const c = indexArray[ y + 1 ][ x + 1 ];
const d = indexArray[ y ][ x + 1 ];
// faces
indices.push( a, b, d );
groupCount += 3;
indices.push( b, c, d );
groupCount += 3;
groupStart += groupCount;
let groupCount = 0;
// vertex
vertices.push( 0, halfHeight * sign, 0 );
// normal
normals.push( 0, sign, 0 );
// uv
// increase index
index ++;
const u = x / radialSegments;
const theta = u * thetaLength + thetaStart;
// vertex
// normal
normals.push( 0, sign, 0 );
// uv
// increase index
index ++;
// generate indices
const c = centerIndexStart + x;
const i = centerIndexEnd + x;
if ( top === true ) {
// face top
indices.push( i, i + 1, c );
} else {
// face bottom
indices.push( i + 1, i, c );
groupCount += 3;
groupStart += groupCount;
copy( source ) {
super.copy( source );
return this;
this.parameters = {
radius: radius,
height: height,
radialSegments: radialSegments,
heightSegments: heightSegments,
openEnded: openEnded,
thetaStart: thetaStart,
thetaLength: thetaLength
};
super();
this.type = 'PolyhedronGeometry';
this.parameters = {
vertices: vertices,
indices: indices,
radius: radius,
detail: detail
};
subdivide( detail );
applyRadius( radius );
generateUVs();
if ( detail === 0 ) {
} else {
// helper functions
// iterate over all faces and apply a subdivision with the given
detail value
getVertexByIndex( indices[ i + 0 ], a );
getVertexByIndex( indices[ i + 1 ], b );
getVertexByIndex( indices[ i + 2 ], c );
// perform subdivision
subdivideFace( a, b, c, detail );
const v = [];
v[ i ] = [];
v[ i ][ j ] = aj;
} else {
const k = Math.floor( j / 2 );
if ( j % 2 === 0 ) {
pushVertex( v[ i ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k ] );
pushVertex( v[ i ][ k ] );
} else {
pushVertex( v[ i ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k + 1 ] );
pushVertex( v[ i + 1 ][ k ] );
// iterate over the entire buffer and apply the radius to each
vertex
vertex.x = vertexBuffer[ i + 0 ];
vertex.y = vertexBuffer[ i + 1 ];
vertex.z = vertexBuffer[ i + 2 ];
vertex.normalize().multiplyScalar( radius );
vertexBuffer[ i + 0 ] = vertex.x;
vertexBuffer[ i + 1 ] = vertex.y;
vertexBuffer[ i + 2 ] = vertex.z;
function generateUVs() {
vertex.x = vertexBuffer[ i + 0 ];
vertex.y = vertexBuffer[ i + 1 ];
vertex.z = vertexBuffer[ i + 2 ];
correctUVs();
correctSeam();
function correctSeam() {
const x0 = uvBuffer[ i + 0 ];
const x1 = uvBuffer[ i + 2 ];
const x2 = uvBuffer[ i + 4 ];
}
}
function correctUVs() {
copy( source ) {
super.copy( source );
return this;
const t = ( 1 + Math.sqrt( 5 ) ) / 2;
const r = 1 / t;
const vertices = [
// (±1/φ, ±φ, 0)
- r, - t, 0, - r, t, 0,
r, - t, 0, r, t, 0,
// (±φ, 0, ±1/φ)
- t, 0, - r, t, 0, - r,
- t, 0, r, t, 0, r
];
const indices = [
3, 11, 7, 3, 7, 15, 3, 15, 13,
7, 19, 17, 7, 17, 6, 7, 6, 15,
17, 4, 8, 17, 8, 10, 17, 10, 6,
8, 0, 16, 8, 16, 2, 8, 2, 10,
0, 12, 1, 0, 1, 18, 0, 18, 16,
6, 10, 2, 6, 2, 13, 6, 13, 15,
2, 16, 18, 2, 18, 3, 2, 3, 13,
18, 1, 9, 18, 9, 11, 18, 11, 3,
4, 14, 12, 4, 12, 0, 4, 0, 8,
11, 9, 5, 11, 5, 19, 11, 19, 7,
19, 5, 14, 19, 14, 4, 19, 4, 17,
1, 12, 14, 1, 14, 5, 1, 5, 9
];
this.type = 'DodecahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
super();
this.type = 'EdgesGeometry';
this.parameters = {
geometry: geometry,
thresholdAngle: thresholdAngle
};
const precisionPoints = 4;
const precision = Math.pow( 10, precisionPoints );
const thresholdDot = Math.cos( DEG2RAD * thresholdAngle );
const indexArr = [ 0, 0, 0 ];
const vertKeys = [ 'a', 'b', 'c' ];
const hashes = new Array( 3 );
if ( indexAttr ) {
indexArr[ 0 ] = indexAttr.getX( i );
indexArr[ 1 ] = indexAttr.getX( i + 1 );
indexArr[ 2 ] = indexAttr.getX( i + 2 );
} else {
indexArr[ 0 ] = i;
indexArr[ 1 ] = i + 1;
indexArr[ 2 ] = i + 2;
const { a, b, c } = _triangle;
a.fromBufferAttribute( positionAttr, indexArr[ 0 ] );
b.fromBufferAttribute( positionAttr, indexArr[ 1 ] );
c.fromBufferAttribute( positionAttr, indexArr[ 2 ] );
_triangle.getNormal( _normal );
continue;
index0: indexArr[ j ],
index1: indexArr[ jNext ],
normal: _normal.clone(),
};
if ( edgeData[ key ] ) {
copy( source ) {
super.copy( source );
return this;
constructor( points ) {
super( points );
this.uuid = generateUUID();
this.type = 'Shape';
this.holes = [];
getPointsHoles( divisions ) {
}
return holesPts;
extractPoints( divisions ) {
return {
};
copy( source ) {
super.copy( source );
this.holes = [];
this.holes.push( hole.clone() );
return this;
toJSON() {
data.uuid = this.uuid;
data.holes = [];
return data;
fromJSON( json ) {
super.fromJSON( json );
this.uuid = json.uuid;
this.holes = [];
for ( let i = 0, l = json.holes.length; i < l; i ++ ) {
return this;
/**
* Port from https://github.com/mapbox/earcut (v2.2.4)
*/
const Earcut = {
// if the shape is not too simple, we'll use z-order curve hash later;
calculate polygon bbox
if ( data.length > 80 * dim ) {
x = data[ i ];
y = data[ i + 1 ];
if ( x < minX ) minX = x;
if ( y < minY ) minY = y;
if ( x > maxX ) maxX = x;
if ( y > maxY ) maxY = y;
// minX, minY and invSize are later used to transform coords into
integers for z-order calculation
invSize = Math.max( maxX - minX, maxY - minY );
invSize = invSize !== 0 ? 32767 / invSize : 0;
}
earcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );
return triangles;
};
// create a circular doubly linked list from polygon points in the specified
winding order
function linkedList( data, start, end, dim, clockwise ) {
let i, last;
} else {
removeNode( last );
last = last.next;
return last;
let p = start,
again;
do {
again = false;
removeNode( p );
p = end = p.prev;
if ( p === p.next ) break;
again = true;
} else {
p = p.next;
return end;
// main ear slicing loop which triangulates a polygon (given as a linked list)
function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
if ( ! ear ) return;
prev = ear.prev;
next = ear.next;
removeNode( ear );
continue;
ear = next;
// if we looped through the whole remaining polygon and can't find any
more ears
if ( ear === stop ) {
break;
// check whether a polygon node forms a valid ear with adjacent nodes
function isEar( ear ) {
const a = ear.prev,
b = ear,
c = ear.next;
// now make sure we don't have other points inside the potential ear
const ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;
// triangle bbox; min & max are calculated like this for speed
const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
let p = c.next;
while ( p !== a ) {
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
area( p.prev, p, p.next ) >= 0 ) return false;
p = p.next;
return true;
// triangle bbox; min & max are calculated like this for speed
const x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),
y0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),
x1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),
y1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );
let p = ear.prevZ,
n = ear.nextZ;
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !
== c &&
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
area( p.prev, p, p.next ) >= 0 ) return false;
p = p.prevZ;
if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !
== c &&
pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) &&
area( n.prev, n, n.next ) >= 0 ) return false;
n = n.nextZ;
if ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !
== c &&
pointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&
area( p.prev, p, p.next ) >= 0 ) return false;
p = p.prevZ;
if ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !
== c &&
pointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) &&
area( n.prev, n, n.next ) >= 0 ) return false;
n = n.nextZ;
}
return true;
let p = start;
do {
const a = p.prev,
b = p.next.next;
p = start = b;
p = p.next;
return filterPoints( p );
// look for a valid diagonal that divides the polygon into two
let a = start;
do {
let b = a.next.next;
while ( b !== a.prev ) {
b = b.next;
a = a.next;
// link every hole into the outer loop, producing a single-ring polygon without
holes
function eliminateHoles( data, holeIndices, outerNode, dim ) {
queue.sort( compareX );
return outerNode;
function compareX( a, b ) {
// find a bridge between vertices that connects hole with an outer ring and link it
function eliminateHole( hole, outerNode ) {
return outerNode;
}
// David Eberly's algorithm for finding a bridge between hole and outer polygon
function findHoleBridge( hole, outerNode ) {
let p = outerNode,
qx = - Infinity,
m;
// find a segment intersected by a ray from the hole's leftmost point to the
left;
// segment's endpoint with lesser x will be potential connection point
do {
qx = x;
m = p.x < p.next.x ? p : p.next;
if ( x === hx ) return m; // hole touches outer segment;
pick leftmost endpoint
p = p.next;
if ( ! m ) return null;
// look for points inside the triangle of hole point, segment intersection
and endpoint;
// if there are no points found, we have a valid connection;
// otherwise choose the point of the minimum angle with the ray as connection
point
const stop = m,
mx = m.x,
my = m.y;
let tanMin = Infinity, tan;
p = m;
do {
if ( hx >= p.x && p.x >= mx && hx !== p.x &&
pointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ?
qx : hx, hy, p.x, p.y ) ) {
m = p;
tanMin = tan;
p = p.next;
return m;
return area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;
let p = start;
do {
p.prevZ.nextZ = null;
p.prevZ = null;
sortLinked( p );
p = list;
list = null;
tail = null;
numMerges = 0;
while ( p ) {
numMerges ++;
q = p;
pSize = 0;
for ( i = 0; i < inSize; i ++ ) {
pSize ++;
q = q.nextZ;
if ( ! q ) break;
qSize = inSize;
e = p;
p = p.nextZ;
pSize --;
} else {
e = q;
q = q.nextZ;
qSize --;
if ( tail ) tail.nextZ = e;
else list = e;
e.prevZ = tail;
tail = e;
p = q;
tail.nextZ = null;
inSize *= 2;
return list;
}
// z-order of a point given coords and inverse of the longer side of data bbox
function zOrder( x, y, minX, minY, invSize ) {
return x | ( y << 1 );
let p = start,
leftmost = start;
do {
if ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) )
leftmost = p;
p = p.next;
return leftmost;
return a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) &&
// doesn't intersect other edges
( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b )
&& // locally visible
( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not
create opposite-facing sectors
equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b,
b.next ) > 0 ); // special zero-length case
if ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are
collinear and p2 lies on p1q1
if ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are
collinear and q2 lies on p1q1
if ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are
collinear and p1 lies on p2q2
if ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are
collinear and q1 lies on p2q2
return false;
return q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <=
Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );
let p = a;
do {
if ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i
&&
intersects( p, p.next, a, b ) ) return true;
p = p.next;
} while ( p !== a );
return false;
let p = a,
inside = false;
const px = ( a.x + b.x ) / 2,
py = ( a.y + b.y ) / 2;
do {
if ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&
( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) +
p.x ) )
inside = ! inside;
p = p.next;
} while ( p !== a );
return inside;
// link two polygon vertices with a bridge; if the vertices belong to the same
ring, it splits polygon into two;
// if one belongs to the outer ring and another to a hole, it merges it into a
single ring
function splitPolygon( a, b ) {
a.next = b;
b.prev = a;
a2.next = an;
an.prev = a2;
b2.next = a2;
a2.prev = b2;
bp.next = b2;
b2.prev = bp;
return b2;
// create a node and optionally link it with previous one (in a circular doubly
linked list)
function insertNode( i, x, y, last ) {
if ( ! last ) {
p.prev = p;
p.next = p;
} else {
p.next = last.next;
p.prev = last;
last.next.prev = p;
last.next = p;
return p;
function removeNode( p ) {
p.next.prev = p.prev;
p.prev.next = p.next;
function Node( i, x, y ) {
// vertex coordinates
this.x = x;
this.y = y;
let sum = 0;
for ( let i = start, j = end - dim; i < end; i += dim ) {
return sum;
class ShapeUtils {
const n = contour.length;
let a = 0.0;
return a * 0.5;
//
holes.forEach( removeDupEndPts );
holeIndices.push( holeIndex );
holeIndex += holes[ i ].length;
addContour( vertices, holes[ i ] );
//
//
faces.push( triangles.slice( i, i + 3 ) );
return faces;
const l = points.length;
points.pop();
/**
* Creates extruded geometry from a path shape.
*
* parameters = {
*
* curveSegments: <int>, // number of points on the curves
* steps: <int>, // number of points for z-side extrusions / used for subdividing
segments of extrude spline too
* depth: <float>, // Depth to extrude the shape
*
* bevelEnabled: <bool>, // turn on bevel
* bevelThickness: <float>, // how deep into the original shape bevel goes
* bevelSize: <float>, // how far from shape outline (including bevelOffset) is
bevel
* bevelOffset: <float>, // how far from shape outline does bevel start
* bevelSegments: <int>, // number of bevel layers
*
* extrudePath: <THREE.Curve> // curve to extrude shape along
*
* UVGenerator: <Object> // object that provides UV generator functions
*
* }
*/
constructor( shapes = new Shape( [ new Vector2( 0.5, 0.5 ), new Vector2( -
0.5, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), options =
{} ) {
super();
this.type = 'ExtrudeGeometry';
this.parameters = {
shapes: shapes,
options: options
};
// build geometry
// functions
// options
//
if ( extrudePath ) {
extrudeByPath = true;
bevelEnabled = false; // bevels not supported for path
extrusion
// console.log(splineTube, 'splineTube',
splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
}
// Safeguards if bevels are not enabled
if ( ! bevelEnabled ) {
bevelSegments = 0;
bevelThickness = 0;
bevelSize = 0;
bevelOffset = 0;
// Variables initialization
if ( reverse ) {
vertices = vertices.reverse();
if ( ShapeUtils.isClockWise( ahole ) ) {
holes[ h ] = ahole.reverse();
/* Vertices */
}
function scalePt2( pt, vec, size ) {
// not collinear
} else {
} else {
direction_eq = true;
} else {
direction_eq = true;
} else {
direction_eq = true;
if ( direction_eq ) {
} else {
if ( j === il ) j = 0;
if ( k === il ) k = 0;
// (j)---(i)---(k)
// console.log('i,j,k', i, j , k)
oneHoleMovements = [];
if ( j === il ) j = 0;
if ( k === il ) k = 0;
// (j)---(i)---(k)
oneHoleMovements[ i ] = getBevelVec( ahole[ i ],
ahole[ j ], ahole[ k ] );
holesMovements.push( oneHoleMovements );
verticesMovements =
verticesMovements.concat( oneHoleMovements );
const t = b / bevelSegments;
const z = bevelThickness * Math.cos( t * Math.PI / 2 );
const bs = bevelSize * Math.sin( t * Math.PI / 2 ) +
bevelOffset;
// contract shape
v( vert.x, vert.y, - z );
// expand holes
v( vert.x, vert.y, - z );
if ( ! extrudeByPath ) {
v( vert.x, vert.y, 0 );
} else {
if ( ! extrudeByPath ) {
const t = b / bevelSegments;
const z = bevelThickness * Math.cos( t * Math.PI / 2 );
const bs = bevelSize * Math.sin( t * Math.PI / 2 ) +
bevelOffset;
// contract shape
// expand holes
if ( ! extrudeByPath ) {
/* Faces */
buildLidFaces();
// Sides faces
buildSideFaces();
function buildLidFaces() {
if ( bevelEnabled ) {
// Bottom faces
// Top faces
} else {
// Bottom faces
// Top faces
function buildSideFaces() {
//, true
layeroffset += ahole.length;
let i = contour.length;
while ( -- i >= 0 ) {
const j = i;
let k = i - 1;
if ( k < 0 ) k = contour.length - 1;
f4( a, b, c, d );
function v( x, y, z ) {
placeholder.push( x );
placeholder.push( y );
placeholder.push( z );
function f3( a, b, c ) {
addVertex( a );
addVertex( b );
addVertex( c );
addUV( uvs[ 0 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 2 ] );
function f4( a, b, c, d ) {
addVertex( a );
addVertex( b );
addVertex( d );
addVertex( b );
addVertex( c );
addVertex( d );
const nextIndex = verticesArray.length / 3;
const uvs = uvgen.generateSideWallUV( scope, verticesArray,
nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );
addUV( uvs[ 0 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 3 ] );
addUV( uvs[ 1 ] );
addUV( uvs[ 2 ] );
addUV( uvs[ 3 ] );
uvArray.push( vector2.x );
uvArray.push( vector2.y );
copy( source ) {
super.copy( source );
return this;
toJSON() {
geometryShapes.push( shape );
const WorldUVGenerator = {
return [
new Vector2( a_x, a_y ),
new Vector2( b_x, b_y ),
new Vector2( c_x, c_y )
];
},
return [
new Vector2( a_x, 1 - a_z ),
new Vector2( b_x, 1 - b_z ),
new Vector2( c_x, 1 - c_z ),
new Vector2( d_x, 1 - d_z )
];
} else {
return [
new Vector2( a_y, 1 - a_z ),
new Vector2( b_y, 1 - b_z ),
new Vector2( c_y, 1 - c_z ),
new Vector2( d_y, 1 - d_z )
];
};
data.shapes = [];
if ( Array.isArray( shapes ) ) {
data.shapes.push( shape.uuid );
} else {
data.shapes.push( shapes.uuid );
return data;
const t = ( 1 + Math.sqrt( 5 ) ) / 2;
const vertices = [
- 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t, 0,
0, - 1, t, 0, 1, t, 0, - 1, - t, 0, 1, - t,
t, 0, - 1, t, 0, 1, - t, 0, - 1, - t, 0, 1
];
const indices = [
0, 11, 5, 0, 5, 1, 0, 1, 7, 0, 7, 10, 0, 10, 11,
1, 5, 9, 5, 11, 4, 11, 10, 2, 10, 7, 6, 7, 1, 8,
3, 9, 4, 3, 4, 2, 3, 2, 6, 3, 6, 8, 3, 8, 9,
4, 9, 5, 2, 4, 11, 6, 2, 10, 8, 6, 7, 9, 8, 1
];
this.type = 'IcosahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
const vertices = [
1, 0, 0, - 1, 0, 0, 0, 1, 0,
0, - 1, 0, 0, 0, 1, 0, 0, - 1
];
const indices = [
0, 2, 4, 0, 4, 3, 0, 3, 5,
0, 5, 2, 1, 2, 5, 1, 5, 3,
1, 3, 4, 1, 4, 2
];
this.type = 'OctahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
}
static fromJSON( data ) {
super();
this.type = 'PlaneGeometry';
this.parameters = {
width: width,
height: height,
widthSegments: widthSegments,
heightSegments: heightSegments
};
//
vertices.push( x, - y, 0 );
normals.push( 0, 0, 1 );
uvs.push( ix / gridX );
uvs.push( 1 - ( iy / gridY ) );
}
}
indices.push( a, b, d );
indices.push( b, c, d );
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
copy( source ) {
super.copy( source );
return this;
super();
this.type = 'RingGeometry';
this.parameters = {
innerRadius: innerRadius,
outerRadius: outerRadius,
thetaSegments: thetaSegments,
phiSegments: phiSegments,
thetaStart: thetaStart,
thetaLength: thetaLength
};
// buffers
// vertex
// normal
normals.push( 0, 0, 1 );
// uv
radius += radiusStep;
}
// indices
const a = segment;
const b = segment + thetaSegments + 1;
const c = segment + thetaSegments + 2;
const d = segment + 1;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
copy( source ) {
super.copy( source );
return this;
constructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5,
- 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {
super();
this.type = 'ShapeGeometry';
this.parameters = {
shapes: shapes,
curveSegments: curveSegments
};
// buffers
// helper variables
let groupStart = 0;
let groupCount = 0;
addShape( shapes );
} else {
addShape( shapes[ i ] );
groupStart += groupCount;
groupCount = 0;
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// helper functions
shapeVertices = shapeVertices.reverse();
shapeHoles[ i ] = shapeHole.reverse();
// indices
copy( source ) {
super.copy( source );
return this;
toJSON() {
geometryShapes.push( shape );
data.shapes = [];
if ( Array.isArray( shapes ) ) {
data.shapes.push( shape.uuid );
}
} else {
data.shapes.push( shapes.uuid );
return data;
super();
this.type = 'SphereGeometry';
this.parameters = {
radius: radius,
widthSegments: widthSegments,
heightSegments: heightSegments,
phiStart: phiStart,
phiLength: phiLength,
thetaStart: thetaStart,
thetaLength: thetaLength
};
let index = 0;
const grid = [];
// buffers
const v = iy / heightSegments;
const u = ix / widthSegments;
// vertex
// normal
// uv
uvs.push( u + uOffset, 1 - v );
verticesRow.push( index ++ );
grid.push( verticesRow );
// indices
const a = grid[ iy ][ ix + 1 ];
const b = grid[ iy ][ ix ];
const c = grid[ iy + 1 ][ ix ];
const d = grid[ iy + 1 ][ ix + 1 ];
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
copy( source ) {
super.copy( source );
return this;
const vertices = [
1, 1, 1, - 1, - 1, 1, - 1, 1, - 1, 1, - 1, - 1
];
const indices = [
2, 1, 0, 0, 3, 2, 1, 3, 0, 2, 3, 1
];
this.type = 'TetrahedronGeometry';
this.parameters = {
radius: radius,
detail: detail
};
super();
this.type = 'TorusGeometry';
this.parameters = {
radius: radius,
tube: tube,
radialSegments: radialSegments,
tubularSegments: tubularSegments,
arc: arc
};
// buffers
// helper variables
// vertex
// uv
uvs.push( i / tubularSegments );
uvs.push( j / radialSegments );
// generate indices
// indices
const a = ( tubularSegments + 1 ) * j + i - 1;
const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
const d = ( tubularSegments + 1 ) * j + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
copy( source ) {
super.copy( source );
return this;
}
static fromJSON( data ) {
super();
this.type = 'TorusKnotGeometry';
this.parameters = {
radius: radius,
tube: tube,
tubularSegments: tubularSegments,
radialSegments: radialSegments,
p: p,
q: q
};
// buffers
// helper variables
calculatePositionOnCurve( u, p, q, radius, P1 );
calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
T.subVectors( P2, P1 );
N.addVectors( P2, P1 );
B.crossVectors( T, N );
N.crossVectors( B, T );
B.normalize();
N.normalize();
// uv
uvs.push( i / tubularSegments );
uvs.push( j / radialSegments );
// generate indices
for ( let j = 1; j <= tubularSegments; j ++ ) {
// indices
const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
const b = ( radialSegments + 1 ) * j + ( i - 1 );
const c = ( radialSegments + 1 ) * j + i;
const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
const cu = Math.cos( u );
const su = Math.sin( u );
const quOverP = q / p * u;
const cs = Math.cos( quOverP );
copy( source ) {
super.copy( source );
return this;
super();
this.type = 'TubeGeometry';
this.parameters = {
path: path,
tubularSegments: tubularSegments,
radius: radius,
radialSegments: radialSegments,
closed: closed
};
// expose internals
this.tangents = frames.tangents;
this.normals = frames.normals;
this.binormals = frames.binormals;
// helper variables
// buffer
generateBufferData();
// build geometry
this.setIndex( indices );
this.setAttribute( 'position', new Float32BufferAttribute( vertices,
3 ) );
this.setAttribute( 'normal', new Float32BufferAttribute( normals,
3 ) );
this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
// functions
function generateBufferData() {
generateSegment( i );
generateUVs();
generateIndices();
function generateSegment( i ) {
P = path.getPointAt( i / tubularSegments, P );
const N = frames.normals[ i ];
const B = frames.binormals[ i ];
// normal
// vertex
function generateIndices() {
const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i -
1 );
const b = ( radialSegments + 1 ) * j + ( i - 1 );
const c = ( radialSegments + 1 ) * j + i;
const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
// faces
indices.push( a, b, d );
indices.push( b, c, d );
function generateUVs() {
uv.x = i / tubularSegments;
uv.y = j / radialSegments;
copy( source ) {
super.copy( source );
this.parameters = Object.assign( {}, source.parameters );
return this;
toJSON() {
data.path = this.parameters.path.toJSON();
return data;
super();
this.type = 'WireframeGeometry';
this.parameters = {
geometry: geometry
};
// buffer
// helper variables
if ( groups.length === 0 ) {
start.fromBufferAttribute( position,
index1 );
end.fromBufferAttribute( position, index2
);
} else {
// non-indexed BufferGeometry
const index1 = 3 * i + j;
const index2 = 3 * i + ( ( j + 1 ) % 3 );
// build geometry
copy( source ) {
super.copy( source );
return this;
return false;
} else {
edges.add( hash1 );
edges.add( hash2 );
return true;
constructor( parameters ) {
super();
this.isShadowMaterial = true;
this.type = 'ShadowMaterial';
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.fog = source.fog;
return this;
constructor( parameters ) {
super( parameters );
this.isRawShaderMaterial = true;
this.type = 'RawShaderMaterial';
constructor( parameters ) {
super();
this.isMeshStandardMaterial = true;
this.type = 'MeshStandardMaterial';
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.roughnessMap = null;
this.metalnessMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.envMapIntensity = 1.0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.roughness = source.roughness;
this.metalness = source.metalness;
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.roughnessMap = source.roughnessMap;
this.metalnessMap = source.metalnessMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.envMapIntensity = source.envMapIntensity;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
constructor( parameters ) {
super();
this.isMeshPhysicalMaterial = true;
this.defines = {
'STANDARD': '',
'PHYSICAL': ''
};
this.type = 'MeshPhysicalMaterial';
this.anisotropyRotation = 0;
this.anisotropyMap = null;
this.clearcoatMap = null;
this.clearcoatRoughness = 0.0;
this.clearcoatRoughnessMap = null;
this.clearcoatNormalScale = new Vector2( 1, 1 );
this.clearcoatNormalMap = null;
this.ior = 1.5;
},
set: function ( reflectivity ) {
}
} );
this.iridescenceMap = null;
this.iridescenceIOR = 1.3;
this.iridescenceThicknessRange = [ 100, 400 ];
this.iridescenceThicknessMap = null;
this.transmissionMap = null;
this.thickness = 0;
this.thicknessMap = null;
this.attenuationDistance = Infinity;
this.attenuationColor = new Color( 1, 1, 1 );
this.specularIntensity = 1.0;
this.specularIntensityMap = null;
this.specularColor = new Color( 1, 1, 1 );
this.specularColorMap = null;
this._anisotropy = 0;
this._clearcoat = 0;
this._dispersion = 0;
this._iridescence = 0;
this._sheen = 0.0;
this._transmission = 0;
this.setValues( parameters );
get anisotropy() {
return this._anisotropy;
this.version ++;
}
this._anisotropy = value;
get clearcoat() {
return this._clearcoat;
this.version ++;
this._clearcoat = value;
get iridescence() {
return this._iridescence;
this.version ++;
this._iridescence = value;
get dispersion() {
return this._dispersion;
this.version ++;
this._dispersion = value;
}
get sheen() {
return this._sheen;
this.version ++;
this._sheen = value;
get transmission() {
return this._transmission;
this.version ++;
this._transmission = value;
copy( source ) {
super.copy( source );
this.defines = {
'STANDARD': '',
'PHYSICAL': ''
};
this.anisotropy = source.anisotropy;
this.anisotropyRotation = source.anisotropyRotation;
this.anisotropyMap = source.anisotropyMap;
this.clearcoat = source.clearcoat;
this.clearcoatMap = source.clearcoatMap;
this.clearcoatRoughness = source.clearcoatRoughness;
this.clearcoatRoughnessMap = source.clearcoatRoughnessMap;
this.clearcoatNormalMap = source.clearcoatNormalMap;
this.clearcoatNormalScale.copy( source.clearcoatNormalScale );
this.dispersion = source.dispersion;
this.ior = source.ior;
this.iridescence = source.iridescence;
this.iridescenceMap = source.iridescenceMap;
this.iridescenceIOR = source.iridescenceIOR;
this.iridescenceThicknessRange =
[ ...source.iridescenceThicknessRange ];
this.iridescenceThicknessMap = source.iridescenceThicknessMap;
this.sheen = source.sheen;
this.sheenColor.copy( source.sheenColor );
this.sheenColorMap = source.sheenColorMap;
this.sheenRoughness = source.sheenRoughness;
this.sheenRoughnessMap = source.sheenRoughnessMap;
this.transmission = source.transmission;
this.transmissionMap = source.transmissionMap;
this.thickness = source.thickness;
this.thicknessMap = source.thicknessMap;
this.attenuationDistance = source.attenuationDistance;
this.attenuationColor.copy( source.attenuationColor );
this.specularIntensity = source.specularIntensity;
this.specularIntensityMap = source.specularIntensityMap;
this.specularColor.copy( source.specularColor );
this.specularColorMap = source.specularColorMap;
return this;
constructor( parameters ) {
super();
this.isMeshPhongMaterial = true;
this.type = 'MeshPhongMaterial';
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.specular.copy( source.specular );
this.shininess = source.shininess;
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
constructor( parameters ) {
super();
this.isMeshToonMaterial = true;
this.type = 'MeshToonMaterial';
this.map = null;
this.gradientMap = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.alphaMap = null;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.gradientMap = source.gradientMap;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.alphaMap = source.alphaMap;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.fog = source.fog;
return this;
constructor( parameters ) {
super();
this.isMeshNormalMaterial = true;
this.type = 'MeshNormalMaterial';
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.flatShading = false;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.flatShading = source.flatShading;
return this;
constructor( parameters ) {
super();
this.isMeshLambertMaterial = true;
this.type = 'MeshLambertMaterial';
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.envMapRotation = new Euler();
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.emissive.copy( source.emissive );
this.emissiveMap = source.emissiveMap;
this.emissiveIntensity = source.emissiveIntensity;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.envMapRotation.copy( source.envMapRotation );
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
}
}
constructor( parameters ) {
super();
this.isMeshDepthMaterial = true;
this.type = 'MeshDepthMaterial';
this.depthPacking = BasicDepthPacking;
this.map = null;
this.alphaMap = null;
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.depthPacking = source.depthPacking;
this.map = source.map;
this.alphaMap = source.alphaMap;
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
return this;
constructor( parameters ) {
super();
this.isMeshDistanceMaterial = true;
this.type = 'MeshDistanceMaterial';
this.map = null;
this.alphaMap = null;
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.map = source.map;
this.alphaMap = source.alphaMap;
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
return this;
constructor( parameters ) {
super();
this.isMeshMatcapMaterial = true;
this.type = 'MeshMatcapMaterial';
this.matcap = null;
this.map = null;
this.bumpMap = null;
this.bumpScale = 1;
this.normalMap = null;
this.normalMapType = TangentSpaceNormalMap;
this.normalScale = new Vector2( 1, 1 );
this.displacementMap = null;
this.displacementScale = 1;
this.displacementBias = 0;
this.alphaMap = null;
this.flatShading = false;
this.fog = true;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.color.copy( source.color );
this.matcap = source.matcap;
this.map = source.map;
this.bumpMap = source.bumpMap;
this.bumpScale = source.bumpScale;
this.normalMap = source.normalMap;
this.normalMapType = source.normalMapType;
this.normalScale.copy( source.normalScale );
this.displacementMap = source.displacementMap;
this.displacementScale = source.displacementScale;
this.displacementBias = source.displacementBias;
this.alphaMap = source.alphaMap;
this.flatShading = source.flatShading;
this.fog = source.fog;
return this;
constructor( parameters ) {
super();
this.isLineDashedMaterial = true;
this.type = 'LineDashedMaterial';
this.scale = 1;
this.dashSize = 3;
this.gapSize = 1;
this.setValues( parameters );
copy( source ) {
super.copy( source );
this.scale = source.scale;
this.dashSize = source.dashSize;
this.gapSize = source.gapSize;
return this;
function compareTime( i, j ) {
const n = times.length;
const result = new Array( n );
for ( let i = 0; i !== n; ++ i ) result[ i ] = i;
result.sort( compareTime );
return result;
return result;
key = jsonKeys[ i ++ ];
if ( Array.isArray( value ) ) {
do {
times.push( key.time );
values.push.apply( values, value ); // push all elements
key = jsonKeys[ i ++ ];
// ...assume THREE.Math-ish
do {
times.push( key.time );
value.toArray( values, values.length );
key = jsonKeys[ i ++ ];
} else {
do {
times.push( key.time );
values.push( value );
key = jsonKeys[ i ++ ];
clip.name = name;
times.push( track.times[ j ] );
tracks.push( track );
clip.tracks = tracks;
// find minimum .times value across all tracks in the trimmed clip
clip.resetDuration();
return clip;
// Make each track's values relative to the values at the reference frame
for ( let i = 0; i < numTracks; ++ i ) {
// Find the track in the target clip whose name and type matches the
reference track
const targetTrack = targetClip.tracks.find( function ( track ) {
} );
let referenceOffset = 0;
const referenceValueSize = referenceTrack.getValueSize();
if
( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
referenceOffset = referenceValueSize / 3;
let targetOffset = 0;
const targetValueSize = targetTrack.getValueSize();
if
( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {
targetOffset = targetValueSize / 3;
} else {
} else {
targetTrack.values[ valueStart + k ] -=
referenceValue[ k ];
}
targetClip.blendMode = AdditiveAnimationBlendMode;
return targetClip;
const AnimationUtils = {
convertArray: convertArray,
isTypedArray: isTypedArray,
getKeyframeOrder: getKeyframeOrder,
sortedArray: sortedArray,
flattenJSON: flattenJSON,
subclip: subclip,
makeClipAdditive: makeClipAdditive
};
/**
* Abstract base class of interpolants over parametric samples.
*
* The parameter domain is one dimensional, typically the time or a path
* along a curve defined by the data.
*
* The sample values can have any dimensionality and derived classes may
* apply special interpretations to the data.
*
* This class provides the interval seek in a Template Method, deferring
* the actual interpolation to derived classes.
*
* Time complexity is O(1) for linear access crossing at most two points
* and O(log N) for random access, where N is the number of positions.
*
* References:
*
* http://www.oodesign.com/template-method-pattern.html
*
*/
class Interpolant {
this.parameterPositions = parameterPositions;
this._cachedIndex = 0;
this.settings = null;
this.DefaultSettings_ = {};
}
evaluate( t ) {
const pp = this.parameterPositions;
let i1 = this._cachedIndex,
t1 = pp[ i1 ],
t0 = pp[ i1 - 1 ];
validate_interval: {
seek: {
let right;
linear_scan: {
if ( t1 === undefined ) {
// after end
i1 = pp.length;
this._cachedIndex = i1;
return this.copySampleValue_( i1 -
1 );
t0 = t1;
t1 = pp[ ++ i1 ];
if ( t < t1 ) {
// looping?
if ( t < t1global ) {
if ( t0 === undefined ) {
// before start
this._cachedIndex = 0;
return this.copySampleValue_( 0 );
t1 = t0;
t0 = pp[ -- i1 - 1 ];
if ( t >= t0 ) {
} // linear scan
// binary search
right = mid;
} else {
i1 = mid + 1;
t1 = pp[ i1 ];
t0 = pp[ i1 - 1 ];
if ( t0 === undefined ) {
this._cachedIndex = 0;
return this.copySampleValue_( 0 );
if ( t1 === undefined ) {
i1 = pp.length;
this._cachedIndex = i1;
return this.copySampleValue_( i1 - 1 );
} // seek
this._cachedIndex = i1;
} // validate_interval
getSettings_() {
copySampleValue_( index ) {
return result;
// empty
/**
* Fast and simple cubic spline interpolant.
*
* It was derived from a Hermitian construction setting the first derivative
* at each sample position to the linear slope between neighboring positions
* over their parameter interval.
*/
this._weightPrev = - 0;
this._offsetPrev = - 0;
this._weightNext = - 0;
this._offsetNext = - 0;
this.DefaultSettings_ = {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
};
const pp = this.parameterPositions;
let iPrev = i1 - 2,
iNext = i1 + 1,
switch ( this.getSettings_().endingStart ) {
case ZeroSlopeEnding:
// f'(t0) = 0
iPrev = i1;
tPrev = 2 * t0 - t1;
break;
case WrapAroundEnding:
break;
default: // ZeroCurvatureEnding
switch ( this.getSettings_().endingEnd ) {
case ZeroSlopeEnding:
// f'(tN) = 0
iNext = i1;
tNext = 2 * t1 - t0;
break;
case WrapAroundEnding:
// use the other end of the curve
iNext = 1;
tNext = t1 + pp[ 1 ] - pp[ 0 ];
break;
default: // ZeroCurvatureEnding
o1 = i1 * stride, o0 = o1 - stride,
oP = this._offsetPrev, oN = this._offsetNext,
wP = this._weightPrev, wN = this._weightNext,
p = ( t - t0 ) / ( t1 - t0 ),
pp = p * p,
ppp = pp * p;
// evaluate polynomials
const sP = - wP * ppp + 2 * wP * pp - wP * p;
const s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP )
* p + 1;
const s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;
const sN = wN * ppp - wN * pp;
result[ i ] =
sP * values[ oP + i ] +
s0 * values[ o0 + i ] +
s1 * values[ o1 + i ] +
sN * values[ oN + i ];
}
return result;
offset1 = i1 * stride,
offset0 = offset1 - stride,
weight1 = ( t - t0 ) / ( t1 - t0 ),
weight0 = 1 - weight1;
result[ i ] =
values[ offset0 + i ] * weight0 +
values[ offset1 + i ] * weight1;
return result;
/**
*
* Interpolant that evaluates to the sample value at the position preceding
* the parameter.
*/
return this.copySampleValue_( i1 - 1 );
}
class KeyframeTrack {
this.name = name;
let json;
} else {
'name': track.name,
'times': convertArray( track.times, Array ),
'values': convertArray( track.values, Array )
};
json.interpolation = interpolation;
InterpolantFactoryMethodDiscrete( result ) {
InterpolantFactoryMethodLinear( result ) {
InterpolantFactoryMethodSmooth( result ) {
setInterpolation( interpolation ) {
let factoryMethod;
switch ( interpolation ) {
case InterpolateDiscrete:
factoryMethod = this.InterpolantFactoryMethodDiscrete;
break;
case InterpolateLinear:
factoryMethod = this.InterpolantFactoryMethodLinear;
break;
case InterpolateSmooth:
factoryMethod = this.InterpolantFactoryMethodSmooth;
break;
this.setInterpolation( this.DefaultInterpolation );
} else {
this.createInterpolant = factoryMethod;
return this;
getInterpolation() {
switch ( this.createInterpolant ) {
case this.InterpolantFactoryMethodDiscrete:
return InterpolateDiscrete;
case this.InterpolantFactoryMethodLinear:
return InterpolateLinear;
case this.InterpolantFactoryMethodSmooth:
return InterpolateSmooth;
getValueSize() {
return this;
// scale all keyframe times by a factor (useful for frame <-> seconds
conversions)
scale( timeScale ) {
times[ i ] *= timeScale;
return this;
// removes keyframes before and after animation without changing any values
within the range [startTime, endTime].
// IMPORTANT: We do not shift around keys to the start of the track time,
because for interpolated keys this will change their values
trim( startTime, endTime ) {
let from = 0,
to = nKeys - 1;
++ from;
-- to;
to = Math.max( to, 1 );
from = to - 1;
return this;
nKeys = times.length;
if ( nKeys === 0 ) {
}
if ( prevTime !== null && prevTime > currTime ) {
prevTime = currTime;
if ( isTypedArray( values ) ) {
if ( isNaN( value ) ) {
return valid;
lastIndex = times.length - 1;
let writeIndex = 1;
if ( ! smoothInterpolation ) {
keep = true;
break;
} else {
keep = true;
// in-place compaction
if ( keep ) {
if ( i !== writeIndex ) {
}
}
++ writeIndex;
if ( lastIndex > 0 ) {
++ writeIndex;
} else {
this.times = times;
this.values = values;
return this;
clone() {
return track;
}
KeyframeTrack.prototype.TimeBufferType = Float32Array;
KeyframeTrack.prototype.ValueBufferType = Float32Array;
KeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;
/**
* A Track of Boolean keyframe values.
*/
class BooleanKeyframeTrack extends KeyframeTrack {
BooleanKeyframeTrack.prototype.ValueTypeName = 'bool';
BooleanKeyframeTrack.prototype.ValueBufferType = Array;
BooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
BooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
BooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
/**
* A Track of keyframe values that represent color.
*/
class ColorKeyframeTrack extends KeyframeTrack {}
ColorKeyframeTrack.prototype.ValueTypeName = 'color';
/**
* A Track of numeric keyframe values.
*/
class NumberKeyframeTrack extends KeyframeTrack {}
NumberKeyframeTrack.prototype.ValueTypeName = 'number';
/**
* Spherical linear unit quaternion interpolant.
*/
alpha = ( t - t0 ) / ( t1 - t0 );
return result;
/**
* A Track of quaternion keyframe values.
*/
class QuaternionKeyframeTrack extends KeyframeTrack {
InterpolantFactoryMethodLinear( result ) {
QuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';
// ValueBufferType is inherited
// DefaultInterpolation is inherited;
QuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
/**
* A Track that interpolates Strings
*/
class StringKeyframeTrack extends KeyframeTrack {
StringKeyframeTrack.prototype.ValueTypeName = 'string';
StringKeyframeTrack.prototype.ValueBufferType = Array;
StringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;
StringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;
StringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;
/**
* A Track of vectored keyframe values.
*/
class VectorKeyframeTrack extends KeyframeTrack {}
VectorKeyframeTrack.prototype.ValueTypeName = 'vector';
class AnimationClip {
this.name = name;
this.tracks = tracks;
this.duration = duration;
this.blendMode = blendMode;
this.uuid = generateUUID();
// this means it should figure out its duration by scanning the tracks
if ( this.duration < 0 ) {
this.resetDuration();
return clip;
const json = {
'name': clip.name,
'duration': clip.duration,
'tracks': tracks,
'uuid': clip.uuid,
'blendMode': clip.blendMode
};
for ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {
return json;
times.push(
( i + numMorphTargets - 1 ) % numMorphTargets,
i,
( i + 1 ) % numMorphTargets );
values.push( 0, 1, 0 );
times.push( numMorphTargets );
values.push( values[ 0 ] );
tracks.push(
new NumberKeyframeTrack(
'.morphTargetInfluences[' +
morphTargetSequence[ i ].name + ']',
times, values
).scale( 1.0 / fps ) );
if ( ! Array.isArray( objectOrClipArray ) ) {
const o = objectOrClipArray;
clipArray = o.geometry && o.geometry.animations || o.animations;
return clipArray[ i ];
return null;
let animationMorphTargets =
animationToMorphTargets[ name ];
if ( ! animationMorphTargets ) {
animationToMorphTargets[ name ] =
animationMorphTargets = [];
animationMorphTargets.push( morphTarget );
return clips;
if ( ! animation ) {
};
let k;
if ( animationKeys[ k ].morphTargets ) {
times.push( animationKey.time );
values.push( ( animationKey.morphTarget ===
morphTargetName ) ? 1 : 0 );
tracks.push( new
NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times,
values ) );
} else {
addNonemptyTrack(
QuaternionKeyframeTrack, boneName + '.quaternion',
animationKeys, 'rot', tracks );
addNonemptyTrack(
VectorKeyframeTrack, boneName + '.scale',
animationKeys, 'scl', tracks );
if ( tracks.length === 0 ) {
return null;
return clip;
resetDuration() {
this.duration = duration;
return this;
trim() {
return this;
}
validate() {
return valid;
optimize() {
this.tracks[ i ].optimize();
return this;
clone() {
toJSON() {
switch ( typeName.toLowerCase() ) {
case 'scalar':
case 'double':
case 'float':
case 'number':
case 'integer':
return NumberKeyframeTrack;
case 'vector':
case 'vector2':
case 'vector3':
case 'vector4':
return VectorKeyframeTrack;
case 'color':
return ColorKeyframeTrack;
case 'quaternion':
return QuaternionKeyframeTrack;
case 'bool':
case 'boolean':
return BooleanKeyframeTrack;
case 'string':
return StringKeyframeTrack;
json.times = times;
json.values = values;
const Cache = {
enabled: false,
files: {},
},
},
},
clear: function () {
this.files = {};
};
class LoadingManager {
this.onStart = undefined;
this.onLoad = onLoad;
this.onProgress = onProgress;
this.onError = onError;
itemsTotal ++;
isLoading = true;
};
itemsLoaded ++;
isLoading = false;
scope.onLoad();
};
scope.onError( url );
}
};
if ( urlModifier ) {
return url;
};
urlModifier = transform;
return this;
};
return this;
};
if ( index !== - 1 ) {
handlers.splice( index, 2 );
return this;
};
if ( regex.test( file ) ) {
return loader;
}
return null;
};
class Loader {
constructor( manager ) {
this.crossOrigin = 'anonymous';
this.withCredentials = false;
this.path = '';
this.resourcePath = '';
this.requestHeader = {};
} );
parse( /* data */ ) {}
setCrossOrigin( crossOrigin ) {
this.crossOrigin = crossOrigin;
return this;
setWithCredentials( value ) {
this.withCredentials = value;
return this;
}
setPath( path ) {
this.path = path;
return this;
setResourcePath( resourcePath ) {
this.resourcePath = resourcePath;
return this;
setRequestHeader( requestHeader ) {
this.requestHeader = requestHeader;
return this;
Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT';
super( message );
this.response = response;
constructor( manager ) {
super( manager );
setTimeout( () => {
this.manager.itemEnd( url );
}, 0 );
return cached;
onLoad: onLoad,
onProgress: onProgress,
onError: onError
} );
return;
// create request
const req = new Request( url, {
headers: new Headers( this.requestHeader ),
credentials: this.withCredentials ? 'include' : 'same-origin',
// An abort controller could be added within a future PR
} );
return response;
readData();
function readData() {
if ( done ) {
controller.close();
} else {
loaded +=
value.byteLength;
const callback =
callbacks[ i ];
if
( callback.onProgress ) callback.onProgress( event );
controller.enqueue( value );
readData();
}, ( e ) => {
controller.error( e );
} );
} );
} else {
} )
.then( response => {
switch ( responseType ) {
case 'arraybuffer':
return response.arrayBuffer();
case 'blob':
return response.blob();
case 'document':
return response.text()
.then( text => {
} );
case 'json':
return response.json();
default:
return response.text();
} else {
// sniff encoding
const re = /charset="?([^;"\s]*)"?/i;
const exec = re.exec( mimeType );
const label = exec && exec[ 1 ] ? exec[ 1
].toLowerCase() : undefined;
const decoder = new TextDecoder( label );
return response.arrayBuffer().then( ab =>
decoder.decode( ab ) );
} )
.then( data => {
} )
.catch( err => {
this.manager.itemError( url );
} )
.finally( () => {
this.manager.itemEnd( url );
} );
this.manager.itemStart( url );
setResponseType( value ) {
this.responseType = value;
return this;
setMimeType( value ) {
this.mimeType = value;
return this;
constructor( manager ) {
super( manager );
try {
} catch ( e ) {
if ( onError ) {
onError( e );
} else {
console.error( e );
scope.manager.itemError( url );
}, onProgress, onError );
parse( json ) {
animations.push( clip );
return animations;
/**
* Abstract Base class to block based textures loader (dds, pvr, ...)
*
* Sub classes have to implement the parse() method which will be used in load().
*/
constructor( manager ) {
super( manager );
let loaded = 0;
function loadTexture( i ) {
images[ i ] = {
width: texDatas.width,
height: texDatas.height,
format: texDatas.format,
mipmaps: texDatas.mipmaps
};
loaded += 1;
if ( loaded === 6 ) {
texture.image = images;
texture.format = texDatas.format;
texture.needsUpdate = true;
}, onProgress, onError );
if ( Array.isArray( url ) ) {
loadTexture( i );
} else {
if ( texDatas.isCubemap ) {
images[ f ] = { mipmaps: [] };
texture.image = images;
} else {
texture.image.width = texDatas.width;
texture.image.height = texDatas.height;
texture.mipmaps = texDatas.mipmaps;
if ( texDatas.mipmapCount === 1 ) {
texture.minFilter = LinearFilter;
texture.format = texDatas.format;
texture.needsUpdate = true;
}, onProgress, onError );
return texture;
constructor( manager ) {
super( manager );
scope.manager.itemStart( url );
setTimeout( function () {
scope.manager.itemEnd( url );
}, 0 );
return cached;
function onImageLoad() {
removeEventListeners();
scope.manager.itemEnd( url );
removeEventListeners();
scope.manager.itemError( url );
scope.manager.itemEnd( url );
function removeEventListeners() {
scope.manager.itemStart( url );
image.src = url;
return image;
constructor( manager ) {
super( manager );
let loaded = 0;
function loadTexture( i ) {
texture.images[ i ] = image;
loaded ++;
if ( loaded === 6 ) {
texture.needsUpdate = true;
}, undefined, onError );
loadTexture( i );
}
return texture;
/**
* Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)
*
* Sub classes have to implement the parse() method which will be used in load().
*/
constructor( manager ) {
super( manager );
let texData;
try {
} catch ( error ) {
onError( error );
} else {
console.error( error );
return;
texture.image.width = texData.width;
texture.image.height = texData.height;
texture.image.data = texData.data;
texture.colorSpace = texData.colorSpace;
texture.flipY = texData.flipY;
texture.format = texData.format;
texture.type = texData.type;
texture.mipmaps = texData.mipmaps;
texture.minFilter = LinearMipmapLinearFilter; //
presumably...
if ( texData.mipmapCount === 1 ) {
texture.minFilter = LinearFilter;
}
texture.generateMipmaps = texData.generateMipmaps;
texture.needsUpdate = true;
}, onProgress, onError );
return texture;
constructor( manager ) {
super( manager );
texture.image = image;
texture.needsUpdate = true;
onLoad( texture );
}, onProgress, onError );
return texture;
this.isLight = true;
this.type = 'Light';
dispose() {
this.color.copy( source.color );
this.intensity = source.intensity;
return this;
toJSON( meta ) {
data.object.color = this.color.getHex();
data.object.intensity = this.intensity;
return data;
this.isHemisphereLight = true;
this.type = 'HemisphereLight';
this.position.copy( Object3D.DEFAULT_UP );
this.updateMatrix();
this.groundColor.copy( source.groundColor );
return this;
class LightShadow {
constructor( camera ) {
this.camera = camera;
this.intensity = 1;
this.bias = 0;
this.normalBias = 0;
this.radius = 1;
this.blurSamples = 8;
this.map = null;
this.mapPass = null;
this.matrix = new Matrix4();
this.autoUpdate = true;
this.needsUpdate = false;
this._viewportCount = 1;
this._viewports = [
new Vector4( 0, 0, 1, 1 )
];
getViewportCount() {
return this._viewportCount;
getFrustum() {
return this._frustum;
updateMatrices( light ) {
_lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );
shadowCamera.position.copy( _lightPositionWorld$1 );
_lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );
shadowCamera.lookAt( _lookTarget$1 );
shadowCamera.updateMatrixWorld();
_projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix,
shadowCamera.matrixWorldInverse );
this._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );
shadowMatrix.set(
0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0
);
shadowMatrix.multiply( _projScreenMatrix$1 );
getViewport( viewportIndex ) {
getFrameExtents() {
return this._frameExtents;
dispose() {
if ( this.map ) {
this.map.dispose();
if ( this.mapPass ) {
this.mapPass.dispose();
copy( source ) {
this.camera = source.camera.clone();
this.intensity = source.intensity;
this.bias = source.bias;
this.radius = source.radius;
this.mapSize.copy( source.mapSize );
return this;
clone() {
toJSON() {
return object;
constructor() {
super( new PerspectiveCamera( 50, 1, 0.5, 500 ) );
this.isSpotLightShadow = true;
this.focus = 1;
updateMatrices( light ) {
camera.fov = fov;
camera.aspect = aspect;
camera.far = far;
camera.updateProjectionMatrix();
super.updateMatrices( light );
copy( source ) {
super.copy( source );
this.focus = source.focus;
return this;
this.isSpotLight = true;
this.type = 'SpotLight';
this.position.copy( Object3D.DEFAULT_UP );
this.updateMatrix();
this.distance = distance;
this.angle = angle;
this.penumbra = penumbra;
this.decay = decay;
this.map = null;
get power() {
// compute the light's luminous power (in lumens) from its intensity
(in candela)
// by convention for a spotlight, luminous power (lm) = π * luminous
intensity (cd)
return this.intensity * Math.PI;
// set the light's intensity (in candela) from the desired luminous
power (in lumens)
this.intensity = power / Math.PI;
dispose() {
this.shadow.dispose();
this.distance = source.distance;
this.angle = source.angle;
this.penumbra = source.penumbra;
this.decay = source.decay;
this.target = source.target.clone();
this.shadow = source.shadow.clone();
return this;
this.isPointLightShadow = true;
this._viewportCount = 6;
this._viewports = [
// These viewports map a cube-map onto a 2D texture with the
// following orientation:
//
// xzXZ
// y Y
//
// X - Positive x direction
// x - Negative x direction
// Y - Positive y direction
// y - Negative y direction
// Z - Positive z direction
// z - Negative z direction
// positive X
new Vector4( 2, 1, 1, 1 ),
// negative X
new Vector4( 0, 1, 1, 1 ),
// positive Z
new Vector4( 3, 1, 1, 1 ),
// negative Z
new Vector4( 1, 1, 1, 1 ),
// positive Y
new Vector4( 3, 0, 1, 1 ),
// negative Y
new Vector4( 1, 0, 1, 1 )
];
this._cubeDirections = [
new Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0,
0, 1 ),
new Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0,
- 1, 0 )
];
this._cubeUps = [
new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0,
1, 0 ),
new Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ), new Vector3( 0, 0,
- 1 )
];
camera.far = far;
camera.updateProjectionMatrix();
_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );
camera.position.copy( _lightPositionWorld );
_lookTarget.copy( camera.position );
_lookTarget.add( this._cubeDirections[ viewportIndex ] );
camera.up.copy( this._cubeUps[ viewportIndex ] );
camera.lookAt( _lookTarget );
camera.updateMatrixWorld();
shadowMatrix.makeTranslation( - _lightPositionWorld.x, -
_lightPositionWorld.y, - _lightPositionWorld.z );
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix,
camera.matrixWorldInverse );
this._frustum.setFromProjectionMatrix( _projScreenMatrix );
this.isPointLight = true;
this.type = 'PointLight';
this.distance = distance;
this.decay = decay;
get power() {
// compute the light's luminous power (in lumens) from its intensity
(in candela)
// for an isotropic light source, luminous power (lm) = 4 π luminous
intensity (cd)
return this.intensity * 4 * Math.PI;
// set the light's intensity (in candela) from the desired luminous
power (in lumens)
this.intensity = power / ( 4 * Math.PI );
dispose() {
this.shadow.dispose();
this.distance = source.distance;
this.decay = source.decay;
this.shadow = source.shadow.clone();
return this;
super();
this.isOrthographicCamera = true;
this.type = 'OrthographicCamera';
this.zoom = 1;
this.view = null;
this.left = left;
this.right = right;
this.top = top;
this.bottom = bottom;
this.near = near;
this.far = far;
this.updateProjectionMatrix();
this.left = source.left;
this.right = source.right;
this.top = source.top;
this.bottom = source.bottom;
this.near = source.near;
this.far = source.far;
this.zoom = source.zoom;
this.view = source.view === null ? null : Object.assign( {},
source.view );
return this;
this.view = {
enabled: true,
fullWidth: 1,
fullHeight: 1,
offsetX: 0,
offsetY: 0,
width: 1,
height: 1
};
this.view.enabled = true;
this.view.fullWidth = fullWidth;
this.view.fullHeight = fullHeight;
this.view.offsetX = x;
this.view.offsetY = y;
this.view.width = width;
this.view.height = height;
this.updateProjectionMatrix();
clearViewOffset() {
this.view.enabled = false;
this.updateProjectionMatrix();
updateProjectionMatrix() {
toJSON( meta ) {
data.object.zoom = this.zoom;
data.object.left = this.left;
data.object.right = this.right;
data.object.top = this.top;
data.object.bottom = this.bottom;
data.object.near = this.near;
data.object.far = this.far;
return data;
constructor() {
this.isDirectionalLightShadow = true;
}
class DirectionalLight extends Light {
this.isDirectionalLight = true;
this.type = 'DirectionalLight';
this.position.copy( Object3D.DEFAULT_UP );
this.updateMatrix();
dispose() {
this.shadow.dispose();
copy( source ) {
super.copy( source );
this.target = source.target.clone();
this.shadow = source.shadow.clone();
return this;
this.isAmbientLight = true;
this.type = 'AmbientLight';
this.isRectAreaLight = true;
this.type = 'RectAreaLight';
this.width = width;
this.height = height;
get power() {
// compute the light's luminous power (in lumens) from its intensity
(in nits)
return this.intensity * this.width * this.height * Math.PI;
// set the light's intensity (in nits) from the desired luminous power
(in lumens)
this.intensity = power / ( this.width * this.height * Math.PI );
copy( source ) {
super.copy( source );
this.width = source.width;
this.height = source.height;
return this;
toJSON( meta ) {
data.object.width = this.width;
data.object.height = this.height;
return data;
/**
* Primary reference:
* https://graphics.stanford.edu/papers/envmap/envmap.pdf
*
* Secondary reference:
* https://www.ppsloan.org/publications/StupidSH36.pdf
*/
class SphericalHarmonics3 {
constructor() {
this.isSphericalHarmonics3 = true;
this.coefficients = [];
set( coefficients ) {
return this;
zero() {
this.coefficients[ i ].set( 0, 0, 0 );
return this;
// band 0
target.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );
// band 1
target.addScaledVector( coeff[ 1 ], 0.488603 * y );
target.addScaledVector( coeff[ 2 ], 0.488603 * z );
target.addScaledVector( coeff[ 3 ], 0.488603 * x );
// band 2
target.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );
target.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );
target.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );
target.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );
target.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );
return target;
// get the irradiance (radiance convolved with cosine lobe) in the direction
of the normal
// target is a Vector3
// https://graphics.stanford.edu/papers/envmap/envmap.pdf
getIrradianceAt( normal, target ) {
// band 0
target.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095
// band 1
target.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π /
3 ) * 0.488603
target.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );
target.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );
// band 2
target.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π /
4 ) * 1.092548
target.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );
target.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // (
π / 4 ) * 0.315392 * 3
target.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );
target.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); //
( π / 4 ) * 0.546274
return target;
add( sh ) {
return this;
addScaledSH( sh, s ) {
return this;
scale( s ) {
this.coefficients[ i ].multiplyScalar( s );
return this;
return this;
equals( sh ) {
return false;
return true;
copy( sh ) {
clone() {
return this;
return array;
// band 0
shBasis[ 0 ] = 0.282095;
// band 1
shBasis[ 1 ] = 0.488603 * y;
shBasis[ 2 ] = 0.488603 * z;
shBasis[ 3 ] = 0.488603 * x;
// band 2
shBasis[ 4 ] = 1.092548 * x * y;
shBasis[ 5 ] = 1.092548 * y * z;
shBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );
shBasis[ 7 ] = 1.092548 * x * z;
shBasis[ 8 ] = 0.546274 * ( x * x - y * y );
this.isLightProbe = true;
this.sh = sh;
copy( source ) {
super.copy( source );
this.sh.copy( source.sh );
return this;
fromJSON( json ) {
return this;
toJSON( meta ) {
data.object.sh = this.sh.toArray();
return data;
constructor( manager ) {
super( manager );
this.textures = {};
try {
} catch ( e ) {
if ( onError ) {
onError( e );
} else {
console.error( e );
scope.manager.itemError( url );
}, onProgress, onError );
parse( json ) {
} else {
material.vertexColors = json.vertexColors;
// Shader Material
switch ( uniform.type ) {
case 't':
material.uniforms[ name ].value =
getTexture( uniform.value );
break;
case 'c':
material.uniforms[ name ].value = new
Color().setHex( uniform.value );
break;
case 'v2':
material.uniforms[ name ].value = new
Vector2().fromArray( uniform.value );
break;
case 'v3':
material.uniforms[ name ].value = new
Vector3().fromArray( uniform.value );
break;
case 'v4':
material.uniforms[ name ].value = new
Vector4().fromArray( uniform.value );
break;
case 'm3':
material.uniforms[ name ].value = new
Matrix3().fromArray( uniform.value );
break;
case 'm4':
material.uniforms[ name ].value = new
Matrix4().fromArray( uniform.value );
break;
default:
material.uniforms[ name ].value =
uniform.value;
// for PointsMaterial
// maps
return material;
setTextures( value ) {
this.textures = value;
return this;
createMaterialFromType( type ) {
const materialLib = {
ShadowMaterial,
SpriteMaterial,
RawShaderMaterial,
ShaderMaterial,
PointsMaterial,
MeshPhysicalMaterial,
MeshStandardMaterial,
MeshPhongMaterial,
MeshToonMaterial,
MeshNormalMaterial,
MeshLambertMaterial,
MeshDepthMaterial,
MeshDistanceMaterial,
MeshBasicMaterial,
MeshMatcapMaterial,
LineDashedMaterial,
LineBasicMaterial,
Material
};
class LoaderUtils {
let s = '';
try {
return s;
// Invalid URL
if ( typeof url !== 'string' || url === '' ) return '';
// Data URI
if ( /^data:.*,.*$/i.test( url ) ) return url;
// Blob URL
if ( /^blob:.*$/i.test( url ) ) return url;
// Relative URL
return path + url;
constructor() {
super();
this.isInstancedBufferGeometry = true;
this.type = 'InstancedBufferGeometry';
this.instanceCount = Infinity;
}
copy( source ) {
super.copy( source );
this.instanceCount = source.instanceCount;
return this;
toJSON() {
data.instanceCount = this.instanceCount;
data.isInstancedBufferGeometry = true;
return data;
constructor( manager ) {
super( manager );
try {
} catch ( e ) {
if ( onError ) {
onError( e );
} else {
console.error( e );
}
scope.manager.itemError( url );
}, onProgress, onError );
parse( json ) {
return ib;
return ab;
if ( attribute.isInterleavedBufferAttribute ) {
} else {
if ( morphAttributes ) {
if ( attribute.isInterleavedBufferAttribute ) {
} else {
const typedArray =
getTypedArray( attribute.type, attribute.array );
bufferAttribute = new
BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );
if ( morphTargetsRelative ) {
geometry.morphTargetsRelative = true;
center.fromArray( boundingSphere.center );
}
return geometry;
constructor( manager ) {
super( manager );
try {
} catch ( error ) {
return;
}, onProgress, onError );
} );
//
hasImages = true;
break;
return object;
return object;
parseShapes( json ) {
return shapes;
} );
// create skeletons
return skeletons;
switch ( data.type ) {
case 'BufferGeometry':
case 'InstancedBufferGeometry':
default:
if ( data.type in Geometries ) {
geometry =
Geometries[ data.type ].fromJSON( data, shapes );
} else {
console.warn( `THREE.ObjectLoader:
Unsupported geometry type "${ data.type }"` );
geometry.uuid = data.uuid;
return geometries;
return materials;
parseAnimations( json ) {
return animations;
let loader;
scope.manager.itemStart( url );
scope.manager.itemEnd( url );
}, undefined, function () {
scope.manager.itemError( url );
scope.manager.itemEnd( url );
} );
}
function deserializeImage( image ) {
} else {
if ( image.data ) {
return {
data: getTypedArray( image.type, image.data ),
width: image.width,
height: image.height
};
} else {
return null;
if ( Array.isArray( url ) ) {
const deserializedImage =
deserializeImage( currentUrl );
imageArray.push( deserializedImage );
} else {
imageArray.push( new
DataTexture( deserializedImage.data, deserializedImage.width,
deserializedImage.height ) );
} else {
return images;
let loader;
} else {
if ( image.data ) {
return {
data: getTypedArray( image.type, image.data ),
width: image.width,
height: image.height
};
} else {
return null;
if ( Array.isArray( url ) ) {
if ( deserializedImage instanceof
HTMLImageElement ) {
imageArray.push( deserializedImage );
} else {
imageArray.push( new
DataTexture( deserializedImage.data, deserializedImage.width,
deserializedImage.height ) );
} else {
return images;
let texture;
if ( Array.isArray( image ) ) {
} else {
} else {
texture.source = source;
texture.uuid = data.uuid;
return textures;
let object;
}
function getMaterial( name ) {
if ( Array.isArray( name ) ) {
return array;
switch ( data.type ) {
case 'Scene':
if ( Number.isInteger( data.background ) ) {
object.background = new
Color( data.background );
} else {
object.fog.name = data.fog.name;
break;
case 'PerspectiveCamera':
break;
case 'OrthographicCamera':
break;
case 'AmbientLight':
break;
case 'DirectionalLight':
break;
case 'PointLight':
break;
case 'RectAreaLight':
break;
case 'SpotLight':
break;
case 'HemisphereLight':
break;
case 'LightProbe':
break;
case 'SkinnedMesh':
break;
case 'Mesh':
break;
case 'InstancedMesh':
break;
case 'BatchedMesh':
object._drawRanges = data.drawRanges;
object._reservedRanges = data.reservedRanges;
object._visibility = data.visibility;
object._active = data.active;
object._bounds = data.bounds.map( bound => {
return {
boxInitialized: bound.boxInitialized,
box: box,
sphereInitialized: bound.sphereInitialized,
sphere: sphere
};
} );
object._maxInstanceCount = data.maxInstanceCount;
object._maxVertexCount = data.maxVertexCount;
object._maxIndexCount = data.maxIndexCount;
object._geometryInitialized = data.geometryInitialized;
object._geometryCount = data.geometryCount;
object._matricesTexture =
getTexture( data.matricesTexture.uuid );
if ( data.colorsTexture !== undefined )
object._colorsTexture = getTexture( data.colorsTexture.uuid );
break;
case 'LOD':
break;
case 'Line':
object = new Line( getGeometry( data.geometry ),
getMaterial( data.material ) );
break;
case 'LineLoop':
break;
case 'LineSegments':
break;
case 'PointCloud':
case 'Points':
break;
case 'Sprite':
break;
case 'Group':
break;
case 'Bone':
break;
default:
object.uuid = data.uuid;
object.matrix.fromArray( data.matrix );
if ( data.matrixAutoUpdate !== undefined )
object.matrixAutoUpdate = data.matrixAutoUpdate;
if ( object.matrixAutoUpdate )
object.matrix.decompose( object.position, object.quaternion, object.scale );
} else {
if ( data.shadow ) {
return object;
} else {
} );
bindLightTargets( object ) {
if ( child.isDirectionalLight || child.isSpotLight ) {
child.target = target;
} else {
} );
const TEXTURE_MAPPING = {
UVMapping: UVMapping,
CubeReflectionMapping: CubeReflectionMapping,
CubeRefractionMapping: CubeRefractionMapping,
EquirectangularReflectionMapping: EquirectangularReflectionMapping,
EquirectangularRefractionMapping: EquirectangularRefractionMapping,
CubeUVReflectionMapping: CubeUVReflectionMapping
};
const TEXTURE_WRAPPING = {
RepeatWrapping: RepeatWrapping,
ClampToEdgeWrapping: ClampToEdgeWrapping,
MirroredRepeatWrapping: MirroredRepeatWrapping
};
const TEXTURE_FILTER = {
NearestFilter: NearestFilter,
NearestMipmapNearestFilter: NearestMipmapNearestFilter,
NearestMipmapLinearFilter: NearestMipmapLinearFilter,
LinearFilter: LinearFilter,
LinearMipmapNearestFilter: LinearMipmapNearestFilter,
LinearMipmapLinearFilter: LinearMipmapLinearFilter
};
constructor( manager ) {
super( manager );
this.isImageBitmapLoader = true;
setOptions( options ) {
this.options = options;
return this;
scope.manager.itemStart( url );
scope.manager.itemEnd( url );
} ).catch( e => {
if ( onError ) onError( e );
} );
return;
scope.manager.itemEnd( url );
}, 0 );
return cached;
return res.blob();
scope.manager.itemEnd( url );
return imageBitmap;
} ).catch( function ( e ) {
if ( onError ) onError( e );
Cache.remove( url );
scope.manager.itemError( url );
scope.manager.itemEnd( url );
} );
let _context;
class AudioContext {
static getContext() {
return _context;
_context = value;
constructor( manager ) {
super( manager );
try {
// Create a copy of the buffer. The `decodeAudioData`
method
// detaches the buffer when complete, preventing reuse.
const bufferCopy = buffer.slice( 0 );
onLoad( audioBuffer );
} ).catch( handleError );
} catch ( e ) {
handleError( e );
}, onProgress, onError );
function handleError( e ) {
if ( onError ) {
onError( e );
} else {
console.error( e );
scope.manager.itemError( url );
class StereoCamera {
constructor() {
this.type = 'StereoCamera';
this.aspect = 1;
this.eyeSep = 0.064;
this._cache = {
focus: null,
fov: null,
aspect: null,
near: null,
far: null,
zoom: null,
eyeSep: null
};
update( camera ) {
if ( needsUpdate ) {
cache.focus = camera.focus;
cache.fov = camera.fov;
cache.aspect = camera.aspect * this.aspect;
cache.near = camera.near;
cache.far = camera.far;
cache.zoom = camera.zoom;
cache.eyeSep = this.eyeSep;
_projectionMatrix.copy( camera.projectionMatrix );
const eyeSepHalf = cache.eyeSep / 2;
const eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;
const ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 )
) / cache.zoom;
let xmin, xmax;
// translate xOffset
_eyeLeft.elements[ 12 ] = - eyeSepHalf;
_eyeRight.elements[ 12 ] = eyeSepHalf;
this.cameraL.projectionMatrix.copy( _projectionMatrix );
this.cameraR.projectionMatrix.copy( _projectionMatrix );
constructor( array = [] ) {
super();
this.isArrayCamera = true;
this.cameras = array;
class Clock {
this.autoStart = autoStart;
this.startTime = 0;
this.oldTime = 0;
this.elapsedTime = 0;
this.running = false;
start() {
this.startTime = now();
this.oldTime = this.startTime;
this.elapsedTime = 0;
this.running = true;
stop() {
this.getElapsedTime();
this.running = false;
this.autoStart = false;
getElapsedTime() {
this.getDelta();
return this.elapsedTime;
getDelta() {
let diff = 0;
this.start();
return 0;
if ( this.running ) {
this.elapsedTime += diff;
return diff;
function now() {
return performance.now();
constructor() {
super();
this.type = 'AudioListener';
this.context = AudioContext.getContext();
this.gain = this.context.createGain();
this.gain.connect( this.context.destination );
this.filter = null;
this.timeDelta = 0;
// private
getInput() {
return this.gain;
removeFilter() {
this.gain.disconnect( this.filter );
this.filter.disconnect( this.context.destination );
this.gain.connect( this.context.destination );
this.filter = null;
return this;
getFilter() {
return this.filter;
setFilter( value ) {
this.gain.disconnect( this.filter );
this.filter.disconnect( this.context.destination );
} else {
this.gain.disconnect( this.context.destination );
this.filter = value;
this.gain.connect( this.filter );
this.filter.connect( this.context.destination );
return this;
getMasterVolume() {
return this.gain.gain.value;
setMasterVolume( value ) {
return this;
updateMatrixWorld( force ) {
super.updateMatrixWorld( force );
this.timeDelta = this._clock.getDelta();
if ( listener.positionX ) {
listener.positionX.linearRampToValueAtTime( _position$1.x,
endTime );
listener.positionY.linearRampToValueAtTime( _position$1.y,
endTime );
listener.positionZ.linearRampToValueAtTime( _position$1.z,
endTime );
listener.forwardX.linearRampToValueAtTime( _orientation$1.x,
endTime );
listener.forwardY.linearRampToValueAtTime( _orientation$1.y,
endTime );
listener.forwardZ.linearRampToValueAtTime( _orientation$1.z,
endTime );
listener.upX.linearRampToValueAtTime( up.x, endTime );
listener.upY.linearRampToValueAtTime( up.y, endTime );
listener.upZ.linearRampToValueAtTime( up.z, endTime );
} else {
constructor( listener ) {
super();
this.type = 'Audio';
this.listener = listener;
this.context = listener.context;
this.gain = this.context.createGain();
this.gain.connect( listener.getInput() );
this.autoplay = false;
this.buffer = null;
this.detune = 0;
this.loop = false;
this.loopStart = 0;
this.loopEnd = 0;
this.offset = 0;
this.duration = undefined;
this.playbackRate = 1;
this.isPlaying = false;
this.hasPlaybackControl = true;
this.source = null;
this.sourceType = 'empty';
this._startedAt = 0;
this._progress = 0;
this._connected = false;
this.filters = [];
getOutput() {
return this.gain;
}
setNodeSource( audioNode ) {
this.hasPlaybackControl = false;
this.sourceType = 'audioNode';
this.source = audioNode;
this.connect();
return this;
setMediaElementSource( mediaElement ) {
this.hasPlaybackControl = false;
this.sourceType = 'mediaNode';
this.source = this.context.createMediaElementSource( mediaElement );
this.connect();
return this;
setMediaStreamSource( mediaStream ) {
this.hasPlaybackControl = false;
this.sourceType = 'mediaStreamNode';
this.source = this.context.createMediaStreamSource( mediaStream );
this.connect();
return this;
setBuffer( audioBuffer ) {
this.buffer = audioBuffer;
this.sourceType = 'buffer';
if ( this.autoplay ) this.play();
return this;
play( delay = 0 ) {
this.isPlaying = true;
this.source = source;
this.setDetune( this.detune );
this.setPlaybackRate( this.playbackRate );
return this.connect();
pause() {
this.source.stop();
this.source.onended = null;
this.isPlaying = false;
}
return this;
stop( delay = 0 ) {
this._progress = 0;
this.isPlaying = false;
return this;
connect() {
if ( this.filters.length > 0 ) {
this.source.connect( this.filters[ 0 ] );
} else {
this.source.connect( this.getOutput() );
this._connected = true;
return this;
disconnect() {
if ( this._connected === false ) {
return;
if ( this.filters.length > 0 ) {
this.source.disconnect( this.filters[ 0 ] );
this.filters[ this.filters.length -
1 ].disconnect( this.getOutput() );
} else {
this.source.disconnect( this.getOutput() );
this._connected = false;
return this;
getFilters() {
return this.filters;
setFilters( value ) {
this.disconnect();
this.filters = value.slice();
this.connect();
} else {
this.filters = value.slice();
return this;
setDetune( value ) {
this.detune = value;
this.source.detune.setTargetAtTime( this.detune,
this.context.currentTime, 0.01 );
return this;
getDetune() {
return this.detune;
getFilter() {
return this.getFilters()[ 0 ];
setFilter( filter ) {
setPlaybackRate( value ) {
this.playbackRate = value;
this.source.playbackRate.setTargetAtTime( this.playbackRate,
this.context.currentTime, 0.01 );
return this;
getPlaybackRate() {
return this.playbackRate;
}
onEnded() {
this.isPlaying = false;
this._progress = 0;
getLoop() {
return this.loop;
setLoop( value ) {
this.loop = value;
this.source.loop = this.loop;
return this;
setLoopStart( value ) {
this.loopStart = value;
return this;
setLoopEnd( value ) {
this.loopEnd = value;
return this;
}
getVolume() {
return this.gain.gain.value;
setVolume( value ) {
return this;
return this;
this.autoplay = source.autoplay;
this.buffer = source.buffer;
this.detune = source.detune;
this.loop = source.loop;
this.loopStart = source.loopStart;
this.loopEnd = source.loopEnd;
this.offset = source.offset;
this.duration = source.duration;
this.playbackRate = source.playbackRate;
this.hasPlaybackControl = source.hasPlaybackControl;
this.sourceType = source.sourceType;
this.filters = source.filters.slice();
return this;
clone( recursive ) {
constructor( listener ) {
super( listener );
this.panner = this.context.createPanner();
this.panner.panningModel = 'HRTF';
this.panner.connect( this.gain );
connect() {
super.connect();
this.panner.connect( this.gain );
disconnect() {
super.disconnect();
this.panner.disconnect( this.gain );
getOutput() {
return this.panner;
getRefDistance() {
return this.panner.refDistance;
setRefDistance( value ) {
this.panner.refDistance = value;
return this;
getRolloffFactor() {
return this.panner.rolloffFactor;
setRolloffFactor( value ) {
this.panner.rolloffFactor = value;
return this;
getDistanceModel() {
return this.panner.distanceModel;
setDistanceModel( value ) {
this.panner.distanceModel = value;
return this;
getMaxDistance() {
return this.panner.maxDistance;
setMaxDistance( value ) {
this.panner.maxDistance = value;
return this;
this.panner.coneInnerAngle = coneInnerAngle;
this.panner.coneOuterAngle = coneOuterAngle;
this.panner.coneOuterGain = coneOuterGain;
return this;
updateMatrixWorld( force ) {
super.updateMatrixWorld( force );
if ( panner.positionX ) {
} else {
class AudioAnalyser {
this.analyser = audio.context.createAnalyser();
this.analyser.fftSize = fftSize;
audio.getOutput().connect( this.analyser );
getFrequencyData() {
this.analyser.getByteFrequencyData( this.data );
return this.data;
getAverageFrequency() {
let value = 0;
const data = this.getFrequencyData();
value += data[ i ];
}
return value / data.length;
class PropertyMixer {
this.binding = binding;
this.valueSize = valueSize;
let mixFunction,
mixFunctionAdditive,
setIdentity;
switch ( typeName ) {
case 'quaternion':
mixFunction = this._slerp;
mixFunctionAdditive = this._slerpAdditive;
setIdentity = this._setAdditiveIdentityQuaternion;
case 'string':
case 'bool':
mixFunction = this._select;
setIdentity = this._setAdditiveIdentityOther;
this._mixBufferRegion = mixFunction;
this._mixBufferRegionAdditive = mixFunctionAdditive;
this._setIdentity = setIdentity;
this._origIndex = 3;
this._addIndex = 4;
this.cumulativeWeight = 0;
this.cumulativeWeightAdditive = 0;
this.useCount = 0;
this.referenceCount = 0;
if ( currentWeight === 0 ) {
currentWeight = weight;
} else {
currentWeight += weight;
const mix = weight / currentWeight;
this._mixBufferRegion( buffer, offset, 0, mix, stride );
this.cumulativeWeight = currentWeight;
}
if ( this.cumulativeWeightAdditive === 0 ) {
// add = identity
this._setIdentity();
weight = this.cumulativeWeight,
weightAdditive = this.cumulativeWeightAdditive,
binding = this.binding;
this.cumulativeWeight = 0;
this.cumulativeWeightAdditive = 0;
if ( weight < 1 ) {
this._mixBufferRegion(
buffer, offset, originalValueOffset, 1 - weight, stride );
if ( weightAdditive > 0 ) {
}
for ( let i = stride, e = stride + stride; i !== e; ++ i ) {
// remember the state of the bound property and copy it to both accus
saveOriginalState() {
this.cumulativeWeight = 0;
this.cumulativeWeightAdditive = 0;
_setAdditiveIdentityNumeric() {
this.buffer[ i ] = 0;
}
_setAdditiveIdentityQuaternion() {
this._setAdditiveIdentityNumeric();
this.buffer[ this._addIndex * this.valueSize + 3 ] = 1;
_setAdditiveIdentityOther() {
// mix functions
if ( t >= 0.5 ) {
const s = 1 - t;
const j = dstOffset + i;
const j = dstOffset + i;
// Attempts to allow node names from any language. ES5's `\w` regexp matches
// only latin characters, and the unicode \p{L} is not yet supported. So
// instead, we exclude reserved characters and match everything else.
const _wordChar = '[^' + _RESERVED_CHARS_RE + ']';
const _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\.', '' ) + ']';
// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.
const _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );
// Property and accessor. May not contain reserved characters. Accessor may
// contain any non-bracket characters.
const _propertyRe = /*@__PURE__*/ /\.(WC+)(?:\[(.+)\])?/.source.replace( 'WC',
_wordChar );
const _trackRe = new RegExp( ''
+ '^'
+ _directoryRe
+ _nodeRe
+ _objectRe
+ _propertyRe
+ '$'
);
class Composite {
this._targetGroup = targetGroup;
this._bindings = targetGroup.subscribe_( path, parsedPath );
bind() {
bindings[ i ].bind();
}
}
unbind() {
bindings[ i ].unbind();
this.path = path;
this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
this.rootNode = rootNode;
} else {
/**
* Replaces spaces with underscores and removes unsupported characters from
* node names, to ensure compatibility with parseTrackName().
*
* @param {string} name Node name to be sanitized.
* @return {string}
*/
static sanitizeNodeName( name ) {
const results = {
// directoryName: matches[ 1 ], // (tschw) currently unused
nodeName: matches[ 2 ],
objectName: matches[ 3 ],
objectIndex: matches[ 4 ],
propertyName: matches[ 5 ], // required
propertyIndex: matches[ 6 ]
};
results.nodeName = results.nodeName.substring( 0,
lastDot );
results.objectName = objectName;
return results;
return root;
return bone;
return childNode;
const result =
searchNodeSubtree( childNode.children );
return null;
};
if ( subTreeNode ) {
return subTreeNode;
return null;
// Getters
// Direct
// EntireArray
this.targetObject.needsUpdate = true;
this.targetObject.matrixWorldNeedsUpdate = true;
// ArrayElement
}
_setValue_arrayElement_setNeedsUpdate( buffer, offset ) {
// HasToFromArray
this.bind();
this.getValue( targetArray, offset );
this.bind();
this.setValue( sourceArray, offset );
if ( ! targetObject ) {
this.node = targetObject;
if ( objectName ) {
case 'materials':
if ( ! targetObject.material ) {
if ( ! targetObject.material.materials ) {
targetObject = targetObject.material.materials;
break;
case 'bones':
if ( ! targetObject.skeleton ) {
console.error( 'THREE.PropertyBinding: Can not
bind to bones as node does not have a skeleton.', this );
return;
targetObject = targetObject.skeleton.bones;
objectIndex = i;
break;
break;
case 'map':
if ( 'map' in targetObject ) {
targetObject = targetObject.map;
break;
if ( ! targetObject.material ) {
if ( ! targetObject.material.map ) {
targetObject = targetObject.material.map;
break;
default:
// resolve property
const nodeProperty = targetObject[ propertyName ];
this.targetObject = targetObject;
versioning = this.Versioning.NeedsUpdate;
versioning = this.Versioning.MatrixWorldNeedsUpdate;
if ( ! targetObject.geometry.morphAttributes ) {
if ( targetObject.morphTargetDictionary[ propertyIndex ] !
== undefined ) {
propertyIndex =
targetObject.morphTargetDictionary[ propertyIndex ];
bindingType = this.BindingType.ArrayElement;
this.resolvedProperty = nodeProperty;
this.propertyIndex = propertyIndex;
bindingType = this.BindingType.HasFromToArray;
this.resolvedProperty = nodeProperty;
bindingType = this.BindingType.EntireArray;
this.resolvedProperty = nodeProperty;
} else {
this.propertyName = propertyName;
unbind() {
this.node = null;
PropertyBinding.Composite = Composite;
PropertyBinding.prototype.BindingType = {
Direct: 0,
EntireArray: 1,
ArrayElement: 2,
HasFromToArray: 3
};
PropertyBinding.prototype.Versioning = {
None: 0,
NeedsUpdate: 1,
MatrixWorldNeedsUpdate: 2
};
PropertyBinding.prototype.GetterByBindingType = [
PropertyBinding.prototype._getValue_direct,
PropertyBinding.prototype._getValue_array,
PropertyBinding.prototype._getValue_arrayElement,
PropertyBinding.prototype._getValue_toArray,
];
PropertyBinding.prototype.SetterByBindingTypeAndVersioning = [
[
// Direct
PropertyBinding.prototype._setValue_direct,
PropertyBinding.prototype._setValue_direct_setNeedsUpdate,
PropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,
], [
// EntireArray
PropertyBinding.prototype._setValue_array,
PropertyBinding.prototype._setValue_array_setNeedsUpdate,
PropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,
], [
// ArrayElement
PropertyBinding.prototype._setValue_arrayElement,
PropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,
PropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,
], [
// HasToFromArray
PropertyBinding.prototype._setValue_fromArray,
PropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,
PropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,
];
/**
*
* A group of objects that receives a shared animation state.
*
* Usage:
*
* - Add objects you would otherwise pass as 'root' to the
* constructor or the .clipAction method of AnimationMixer.
*
* - Instead pass this object as 'root'.
*
* - You can also add and remove objects later when the mixer
* is running.
*
* Note:
*
* Objects of this class appear as one object to the mixer,
* so cache control of the individual objects must be done
* on the group.
*
* Limitation:
*
* - The animated properties must be compatible among the
* all objects in the group.
*
* - A single property can either be controlled through a
* target group or directly, but not both.
*/
class AnimationObjectGroup {
constructor() {
this.isAnimationObjectGroup = true;
this.uuid = generateUUID();
this.nCachedObjects_ = 0; // threshold
// note: read by PropertyBinding.Composite
this.stats = {
objects: {
get total() {
return scope._objects.length;
},
get inUse() {
}
},
get bindingsPerObject() {
return scope._bindings.length;
};
add() {
} // for arguments
this.nCachedObjects_ = nCachedObjects;
remove() {
} // for arguments
this.nCachedObjects_ = nCachedObjects;
} else {
if ( lastIndex > 0 ) {
bindingsForPath[ index ] =
bindingsForPath[ lastIndex ];
bindingsForPath.pop();
} // cached or active
} // if object is known
} // for arguments
this.nCachedObjects_ = nCachedObjects;
index = bindings.length;
paths.push( path );
parsedPaths.push( parsedPath );
bindings.push( bindingsForPath );
return bindingsForPath;
unsubscribe_( path ) {
class AnimationAction {
this._mixer = mixer;
this._clip = clip;
this._localRoot = localRoot;
this.blendMode = blendMode;
const interpolantSettings = {
endingStart: ZeroCurvatureEnding,
endingEnd: ZeroCurvatureEnding
};
this._interpolantSettings = interpolantSettings;
this._timeScaleInterpolant = null;
this._weightInterpolant = null;
this.loop = LoopRepeat;
this._loopCount = - 1;
this.timeScale = 1;
this._effectiveTimeScale = 1;
this.weight = 1;
this._effectiveWeight = 1;
play() {
this._mixer._activateAction( this );
return this;
stop() {
this._mixer._deactivateAction( this );
return this.reset();
reset() {
this.paused = false;
this.enabled = true;
return this.stopFading().stopWarping();
isRunning() {
startAt( time ) {
this._startTime = time;
return this;
this.loop = mode;
this.repetitions = repetitions;
return this;
// Weight
this.weight = weight;
return this.stopFading();
return this._effectiveWeight;
fadeIn( duration ) {
fadeOut( duration ) {
fadeOutAction.fadeOut( duration );
this.fadeIn( duration );
if ( warp ) {
return this;
stopFading() {
this._weightInterpolant = null;
this._mixer._takeBackControlInterpolant( weightInterpolant );
return this;
this.timeScale = timeScale;
this._effectiveTimeScale = this.paused ? 0 : timeScale;
return this.stopWarping();
return this._effectiveTimeScale;
}
setDuration( duration ) {
return this.stopWarping();
syncWith( action ) {
this.time = action.time;
this.timeScale = action.timeScale;
return this.stopWarping();
halt( duration ) {
interpolant = mixer._lendControlInterpolant();
this._timeScaleInterpolant = interpolant;
times[ 0 ] = now;
times[ 1 ] = now + duration;
return this;
stopWarping() {
this._timeScaleInterpolant = null;
this._mixer._takeBackControlInterpolant( timeScaleInterpolant );
return this;
// Object Accessors
getMixer() {
return this._mixer;
getClip() {
return this._clip;
getRoot() {
// Interna
if ( ! this.enabled ) {
this._updateWeight( time );
return;
deltaTime = 0;
} else {
if ( weight > 0 ) {
switch ( this.blendMode ) {
case AdditiveAnimationBlendMode:
break;
case NormalAnimationBlendMode:
default:
_updateWeight( time ) {
let weight = 0;
if ( this.enabled ) {
weight = this.weight;
const interpolant = this._weightInterpolant;
weight *= interpolantValue;
this.stopFading();
if ( interpolantValue === 0 ) {
this._effectiveWeight = weight;
return weight;
_updateTimeScale( time ) {
let timeScale = 0;
if ( ! this.paused ) {
timeScale = this.timeScale;
timeScale *= interpolantValue;
this.stopWarping();
if ( timeScale === 0 ) {
} else {
this._effectiveTimeScale = timeScale;
return timeScale;
_updateTime( deltaTime ) {
if ( deltaTime === 0 ) {
if ( loopCount === - 1 ) {
// just started
this._loopCount = 0;
this._setEndings( true, true, false );
handle_stop: {
time = duration;
time = 0;
} else {
this.time = time;
break handle_stop;
this.time = time;
this._mixer.dispatchEvent( {
type: 'finished', action: this,
direction: deltaTime < 0 ? - 1 : 1
} );
if ( loopCount === - 1 ) {
// just started
if ( deltaTime >= 0 ) {
loopCount = 0;
} else {
// wrap around
if ( pending <= 0 ) {
this.time = time;
this._mixer.dispatchEvent( {
type: 'finished', action: this,
direction: deltaTime > 0 ? 1 : - 1
} );
} else {
// keep running
if ( pending === 1 ) {
} else {
this._loopCount = loopCount;
this.time = time;
this._mixer.dispatchEvent( {
type: 'loop', action: this, loopDelta:
loopDelta
} );
} else {
this.time = time;
return time;
}
_setEndings( atStart, atEnd, pingPong ) {
if ( pingPong ) {
settings.endingStart = ZeroSlopeEnding;
settings.endingEnd = ZeroSlopeEnding;
} else {
if ( atStart ) {
settings.endingStart = this.zeroSlopeAtStart ?
ZeroSlopeEnding : ZeroCurvatureEnding;
} else {
settings.endingStart = WrapAroundEnding;
if ( atEnd ) {
settings.endingEnd = this.zeroSlopeAtEnd ?
ZeroSlopeEnding : ZeroCurvatureEnding;
} else {
settings.endingEnd = WrapAroundEnding;
interpolant = mixer._lendControlInterpolant();
this._weightInterpolant = interpolant;
times[ 0 ] = now;
values[ 0 ] = weightNow;
times[ 1 ] = now + duration;
values[ 1 ] = weightThen;
return this;
constructor( root ) {
super();
this._root = root;
this._initMemoryManager();
this._accuIndex = 0;
this.time = 0;
this.timeScale = 1.0;
bindingsByName = {};
bindingsByRoot[ rootUuid ] = bindingsByName;
++ binding.referenceCount;
bindings[ i ] = binding;
} else {
binding = bindings[ i ];
if ( binding !== undefined ) {
++ binding.referenceCount;
this._addInactiveBinding( binding, rootUuid,
trackName );
continue;
++ binding.referenceCount;
this._addInactiveBinding( binding, rootUuid, trackName );
bindings[ i ] = binding;
_activateAction( action ) {
if ( ! this._isActiveAction( action ) ) {
this._bindAction( action,
actionsForClip && actionsForClip.knownActions[ 0 ] );
if ( binding.useCount ++ === 0 ) {
this._lendBinding( binding );
binding.saveOriginalState();
this._lendAction( action );
_deactivateAction( action ) {
if ( this._isActiveAction( action ) ) {
if ( -- binding.useCount === 0 ) {
binding.restoreOriginalState();
this._takeBackBinding( binding );
this._takeBackAction( action );
// Memory manager
_initMemoryManager() {
this._actionsByClip = {};
// inside:
// {
// knownActions: Array< AnimationAction > - used as prototypes
// actionByRoot: AnimationAction - lookup
// }
this._bindings = []; // 'nActiveBindings' followed by inactive ones
this._nActiveBindings = 0;
this.stats = {
actions: {
get total() {
return scope._actions.length;
},
get inUse() {
return scope._nActiveActions;
}
},
bindings: {
get total() {
return scope._bindings.length;
},
get inUse() {
return scope._nActiveBindings;
}
},
controlInterpolants: {
get total() {
return scope._controlInterpolants.length;
},
get inUse() {
return scope._nActiveControlInterpolants;
}
}
};
_isActiveAction( action ) {
const index = action._cacheIndex;
return index !== null && index < this._nActiveActions;
actionsForClip = {
knownActions: [ action ],
actionByRoot: {}
};
action._byClipCacheIndex = 0;
} else {
action._byClipCacheIndex = knownActions.length;
knownActions.push( action );
action._cacheIndex = actions.length;
actions.push( action );
_removeInactiveAction( action ) {
lastInactiveAction._cacheIndex = cacheIndex;
actions[ cacheIndex ] = lastInactiveAction;
actions.pop();
action._cacheIndex = null;
byClipCacheIndex = action._byClipCacheIndex;
lastKnownAction._byClipCacheIndex = byClipCacheIndex;
knownActionsForClip[ byClipCacheIndex ] = lastKnownAction;
knownActionsForClip.pop();
action._byClipCacheIndex = null;
if ( knownActionsForClip.length === 0 ) {
this._removeInactiveBindingsForAction( action );
_removeInactiveBindingsForAction( action ) {
if ( -- binding.referenceCount === 0 ) {
this._removeInactiveBinding( binding );
_lendAction( action ) {
action._cacheIndex = lastActiveIndex;
actions[ lastActiveIndex ] = action;
firstInactiveAction._cacheIndex = prevIndex;
actions[ prevIndex ] = firstInactiveAction;
_takeBackAction( action ) {
firstInactiveIndex = -- this._nActiveActions,
action._cacheIndex = firstInactiveIndex;
actions[ firstInactiveIndex ] = action;
lastActiveAction._cacheIndex = prevIndex;
actions[ prevIndex ] = lastActiveAction;
bindingByName = {};
bindingsByRoot[ rootUuid ] = bindingByName;
binding._cacheIndex = bindings.length;
bindings.push( binding );
_removeInactiveBinding( binding ) {
lastInactiveBinding._cacheIndex = cacheIndex;
bindings[ cacheIndex ] = lastInactiveBinding;
bindings.pop();
_lendBinding( binding ) {
binding._cacheIndex = lastActiveIndex;
bindings[ lastActiveIndex ] = binding;
firstInactiveBinding._cacheIndex = prevIndex;
bindings[ prevIndex ] = firstInactiveBinding;
_takeBackBinding( binding ) {
firstInactiveIndex = -- this._nActiveBindings,
binding._cacheIndex = firstInactiveIndex;
bindings[ firstInactiveIndex ] = binding;
lastActiveBinding._cacheIndex = prevIndex;
bindings[ prevIndex ] = lastActiveBinding;
interpolant.__cacheIndex = lastActiveIndex;
interpolants[ lastActiveIndex ] = interpolant;
return interpolant;
_takeBackControlInterpolant( interpolant ) {
firstInactiveIndex = -- this._nActiveControlInterpolants,
interpolant.__cacheIndex = firstInactiveIndex;
interpolants[ firstInactiveIndex ] = interpolant;
lastActiveInterpolant.__cacheIndex = prevIndex;
interpolants[ prevIndex ] = lastActiveInterpolant;
} else {
blendMode = NormalAnimationBlendMode;
return existingAction;
return newAction;
return null;
actions[ i ].stop();
return this;
deltaTime *= this.timeScale;
accuIndex = this._accuIndex ^= 1;
return this;
return this._root;
this._deactivateAction( action );
action._cacheIndex = null;
action._byClipCacheIndex = null;
lastInactiveAction._cacheIndex = cacheIndex;
actions[ cacheIndex ] = lastInactiveAction;
actions.pop();
this._removeInactiveBindingsForAction( action );
this._deactivateAction( action );
this._removeInactiveAction( action );
this._deactivateAction( action );
this._removeInactiveAction( action );
}
this.isRenderTarget3D = true;
this.depth = depth;
this.texture.isRenderTargetTexture = true;
this.isRenderTargetArray = true;
this.depth = depth;
this.texture.isRenderTargetTexture = true;
class Uniform {
constructor( value ) {
this.value = value;
clone() {
}
let _id$1 = 0;
constructor() {
super();
this.isUniformsGroup = true;
this.name = '';
this.usage = StaticDrawUsage;
this.uniforms = [];
add( uniform ) {
this.uniforms.push( uniform );
return this;
remove( uniform ) {
return this;
setName( name ) {
this.name = name;
return this;
setUsage( value ) {
this.usage = value;
return this;
dispose() {
return this;
}
copy( source ) {
this.name = source.name;
this.usage = source.usage;
this.uniforms.length = 0;
return this;
clone() {
this.isInstancedInterleavedBuffer = true;
this.meshPerAttribute = meshPerAttribute;
copy( source ) {
super.copy( source );
this.meshPerAttribute = source.meshPerAttribute;
return this;
}
clone( data ) {
ib.meshPerAttribute = this.meshPerAttribute;
return ib;
toJSON( data ) {
json.isInstancedInterleavedBuffer = true;
json.meshPerAttribute = this.meshPerAttribute;
return json;
class GLBufferAttribute {
this.isGLBufferAttribute = true;
this.name = '';
this.buffer = buffer;
this.type = type;
this.itemSize = itemSize;
this.elementSize = elementSize;
this.count = count;
this.version = 0;
setBuffer( buffer ) {
this.buffer = buffer;
return this;
this.type = type;
this.elementSize = elementSize;
return this;
setItemSize( itemSize ) {
this.itemSize = itemSize;
return this;
setCount( count ) {
this.count = count;
return this;
class Raycaster {
this.near = near;
this.far = far;
this.camera = null;
this.layers = new Layers();
this.params = {
Mesh: {},
Line: { threshold: 1 },
LOD: {},
Points: { threshold: 1 },
Sprite: {}
};
this.ray.origin.setFromMatrixPosition( camera.matrixWorld );
this.ray.direction.set( coords.x, coords.y,
0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();
this.camera = camera;
} else if ( camera.isOrthographicCamera ) {
} else {
setFromXRController( controller ) {
_matrix.identity().extractRotation( controller.matrixWorld );
this.ray.origin.setFromMatrixPosition( controller.matrixWorld );
this.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix );
return this;
intersects.sort( ascSort );
return intersects;
intersects.sort( ascSort );
return intersects;
}
}
function ascSort( a, b ) {
if ( object.layers.test( raycaster.layers ) ) {
/**
* Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system
*
* phi (the polar angle) is measured from the positive y-axis. The positive y-axis
is up.
* theta (the azimuthal angle) is measured from the positive z-axis.
*/
class Spherical {
this.radius = radius;
this.phi = phi; // polar angle
this.theta = theta; // azimuthal angle
return this;
this.radius = radius;
this.phi = phi;
this.theta = theta;
return this;
copy( other ) {
this.radius = other.radius;
this.phi = other.phi;
this.theta = other.theta;
return this;
return this;
setFromVector3( v ) {
setFromCartesianCoords( 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( clamp( y / this.radius, - 1, 1 ) );
return this;
clone() {
}
/**
* Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system
*/
class Cylindrical {
return this;
this.radius = radius;
this.theta = theta;
this.y = y;
return this;
copy( other ) {
this.radius = other.radius;
this.theta = other.theta;
this.y = other.y;
return this;
setFromVector3( v ) {
setFromCartesianCoords( x, y, z ) {
this.radius = Math.sqrt( x * x + z * z );
this.theta = Math.atan2( x, z );
this.y = y;
return this;
clone() {
}
}
class Matrix2 {
Matrix2.prototype.isMatrix2 = true;
this.elements = [
1, 0,
0, 1,
];
identity() {
this.set(
1, 0,
0, 1,
);
return this;
return this;
const te = this.elements;
return this;
this.isBox2 = true;
this.min = min;
this.max = max;
this.min.copy( min );
this.max.copy( max );
return this;
setFromPoints( points ) {
this.makeEmpty();
this.expandByPoint( points[ i ] );
return this;
return this;
clone() {
copy( box ) {
this.min.copy( box.min );
this.max.copy( box.max );
return this;
}
makeEmpty() {
return this;
isEmpty() {
// this is a more robust check for empty than ( volume <= 0 ) because
volume can get positive with two negative axes
getCenter( target ) {
getSize( target ) {
expandByPoint( point ) {
this.min.min( point );
this.max.max( point );
return this;
expandByVector( vector ) {
this.min.sub( vector );
this.max.add( vector );
return this;
expandByScalar( scalar ) {
this.min.addScalar( - scalar );
this.max.addScalar( scalar );
return this;
}
containsPoint( point ) {
containsBox( box ) {
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 )
);
intersectsBox( box ) {
distanceToPoint( point ) {
intersect( box ) {
this.min.max( box.min );
this.max.min( box.max );
if ( this.isEmpty() ) this.makeEmpty();
return this;
}
union( box ) {
this.min.min( box.min );
this.max.max( box.max );
return this;
translate( offset ) {
this.min.add( offset );
this.max.add( offset );
return this;
equals( box ) {
class Line3 {
this.start = start;
this.end = end;
this.start.copy( start );
this.end.copy( end );
return this;
copy( line ) {
this.start.copy( line.start );
this.end.copy( line.end );
return this;
getCenter( target ) {
return target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );
delta( target ) {
distanceSq() {
distance() {
at( t, target ) {
if ( clampToLine ) {
t = clamp( t, 0, 1 );
return t;
applyMatrix4( matrix ) {
this.start.applyMatrix4( matrix );
this.end.applyMatrix4( matrix );
return this;
equals( line ) {
clone() {
super();
this.light = light;
this.matrixAutoUpdate = false;
this.color = color;
this.type = 'SpotLightHelper';
const positions = [
0, 0, 0, 0, 0, 1,
0, 0, 0, 1, 0, 1,
0, 0, 0, - 1, 0, 1,
0, 0, 0, 0, 1, 1,
0, 0, 0, 0, - 1, 1
];
const p1 = ( i / l ) * Math.PI * 2;
const p2 = ( j / l ) * Math.PI * 2;
positions.push(
Math.cos( p1 ), Math.sin( p1 ), 1,
Math.cos( p2 ), Math.sin( p2 ), 1
);
this.update();
dispose() {
this.cone.geometry.dispose();
this.cone.material.dispose();
update() {
// update the local matrix based on the parent and light target
transforms
if ( this.parent ) {
this.parent.updateWorldMatrix( true );
this.matrix
.copy( this.parent.matrixWorld )
.invert()
.multiply( this.light.matrixWorld );
} else {
this.matrix.copy( this.light.matrixWorld );
this.matrixWorld.copy( this.light.matrixWorld );
_vector$3.setFromMatrixPosition( this.light.target.matrixWorld );
this.cone.lookAt( _vector$3 );
this.cone.material.color.set( this.color );
} else {
this.cone.material.color.copy( this.light.color );
}
constructor( object ) {
vertices.push( 0, 0, 0 );
vertices.push( 0, 0, 0 );
colors.push( color1.r, color1.g, color1.b );
colors.push( color2.r, color2.g, color2.b );
this.isSkeletonHelper = true;
this.type = 'SkeletonHelper';
this.root = object;
this.bones = bones;
this.matrix = object.matrixWorld;
this.matrixAutoUpdate = false;
updateMatrixWorld( force ) {
_boneMatrix.multiplyMatrices( _matrixWorldInv,
bone.matrixWorld );
_vector$2.setFromMatrixPosition( _boneMatrix );
position.setXYZ( j, _vector$2.x, _vector$2.y,
_vector$2.z );
_boneMatrix.multiplyMatrices( _matrixWorldInv,
bone.parent.matrixWorld );
_vector$2.setFromMatrixPosition( _boneMatrix );
position.setXYZ( j + 1, _vector$2.x, _vector$2.y,
_vector$2.z );
j += 2;
super.updateMatrixWorld( force );
dispose() {
this.geometry.dispose();
this.material.dispose();
return boneList;
this.light = light;
this.color = color;
this.type = 'PointLightHelper';
this.matrix = this.light.matrixWorld;
this.matrixAutoUpdate = false;
this.update();
/*
// TODO: delete this comment?
const distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );
const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog:
false, wireframe: true, opacity: 0.1, transparent: true } );
const d = light.distance;
if ( d === 0.0 ) {
this.lightDistance.visible = false;
} else {
this.lightDistance.scale.set( d, d, d );
this.add( this.lightDistance );
*/
}
dispose() {
this.geometry.dispose();
this.material.dispose();
update() {
this.material.color.set( this.color );
} else {
this.material.color.copy( this.light.color );
/*
const d = this.light.distance;
if ( d === 0.0 ) {
this.lightDistance.visible = false;
} else {
this.lightDistance.visible = true;
this.lightDistance.scale.set( d, d, d );
}
*/
super();
this.light = light;
this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;
this.color = color;
this.type = 'HemisphereLightHelper';
this.update();
dispose() {
this.children[ 0 ].geometry.dispose();
this.children[ 0 ].material.dispose();
update() {
this.material.color.set( this.color );
} else {
_color1.copy( this.light.color );
_color2.copy( this.light.groundColor );
colors.needsUpdate = true;
color.toArray( colors, j ); j += 3;
color.toArray( colors, j ); j += 3;
color.toArray( colors, j ); j += 3;
color.toArray( colors, j ); j += 3;
this.type = 'GridHelper';
dispose() {
this.geometry.dispose();
this.material.dispose();
}
class PolarGridHelper extends LineSegments {
if ( sectors > 1 ) {
vertices.push( 0, 0, 0 );
vertices.push( x, 0, z );
// first vertex
let x = Math.sin( v ) * r;
let z = Math.cos( v ) * r;
vertices.push( x, 0, z );
colors.push( color.r, color.g, color.b );
// second vertex
v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
x = Math.sin( v ) * r;
z = Math.cos( v ) * r;
vertices.push( x, 0, z );
colors.push( color.r, color.g, color.b );
this.type = 'PolarGridHelper';
dispose() {
this.geometry.dispose();
this.material.dispose();
super();
this.light = light;
this.matrix = light.matrixWorld;
this.matrixAutoUpdate = false;
this.color = color;
this.type = 'DirectionalLightHelper';
this.update();
dispose() {
this.lightPlane.geometry.dispose();
this.lightPlane.material.dispose();
this.targetLine.geometry.dispose();
this.targetLine.material.dispose();
update() {
_v1.setFromMatrixPosition( this.light.matrixWorld );
_v2.setFromMatrixPosition( this.light.target.matrixWorld );
_v3.subVectors( _v2, _v1 );
this.lightPlane.lookAt( _v2 );
this.lightPlane.material.color.set( this.color );
this.targetLine.material.color.set( this.color );
} else {
this.lightPlane.material.color.copy( this.light.color );
this.targetLine.material.color.copy( this.light.color );
this.targetLine.lookAt( _v2 );
this.targetLine.scale.z = _v3.length();
}
const _vector = /*@__PURE__*/ new Vector3();
const _camera = /*@__PURE__*/ new Camera();
/**
* - shows frustum, line of sight and up of the camera
* - suitable for fast updates
* - based on frustum visualization in lightgl.js shadowmap example
* https://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html
*/
constructor( camera ) {
// near
// far
// sides
// cone
// up
// target
addLine( 'c', 't' );
addLine( 'p', 'c' );
// cross
function addLine( a, b ) {
addPoint( a );
addPoint( b );
function addPoint( id ) {
vertices.push( 0, 0, 0 );
colors.push( 0, 0, 0 );
pointMap[ id ] = [];
this.type = 'CameraHelper';
this.camera = camera;
if ( this.camera.updateProjectionMatrix )
this.camera.updateProjectionMatrix();
this.matrix = camera.matrixWorld;
this.matrixAutoUpdate = false;
this.pointMap = pointMap;
this.update();
// colors
// near
// far
// sides
// cone
// up
colorAttribute.setXYZ( 32, up.r, up.g, up.b );
colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2
colorAttribute.setXYZ( 34, up.r, up.g, up.b );
colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3
colorAttribute.setXYZ( 36, up.r, up.g, up.b );
colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1
// target
// cross
colorAttribute.needsUpdate = true;
update() {
const w = 1, h = 1;
_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
// center / target
setPoint( 'c', pointMap, geometry, _camera, 0, 0, nearZ );
setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
// near
// up
// cross
dispose() {
this.geometry.dispose();
this.material.dispose();
}
const _box = /*@__PURE__*/ new Box3();
this.object = object;
this.type = 'BoxHelper';
this.matrixAutoUpdate = false;
this.update();
update( object ) {
_box.setFromObject( this.object );
if ( _box.isEmpty() ) return;
/*
5____4
1/___0/|
| 6__|_7
2/___3/
position.needsUpdate = true;
this.geometry.computeBoundingSphere();
setFromObject( object ) {
this.object = object;
this.update();
return this;
this.object = source.object;
return this;
dispose() {
this.geometry.dispose();
this.material.dispose();
const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, -
1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
this.box = box;
this.type = 'Box3Helper';
this.geometry.computeBoundingSphere();
updateMatrixWorld( force ) {
if ( box.isEmpty() ) return;
box.getCenter( this.position );
box.getSize( this.scale );
this.scale.multiplyScalar( 0.5 );
super.updateMatrixWorld( force );
dispose() {
this.geometry.dispose();
this.material.dispose();
const positions = [ 1, - 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, 1,
0, - 1, - 1, 0, 1, - 1, 0, 1, 1, 0 ];
this.type = 'PlaneHelper';
this.plane = plane;
this.size = size;
const positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, -
1, 0, 1, - 1, 0 ];
updateMatrixWorld( force ) {
this.position.set( 0, 0, 0 );
this.lookAt( this.plane.normal );
this.translateZ( - this.plane.constant );
super.updateMatrixWorld( force );
dispose() {
this.geometry.dispose();
this.material.dispose();
this.children[ 0 ].geometry.dispose();
this.children[ 0 ].material.dispose();
super();
this.type = 'ArrowHelper';
this.position.copy( origin );
this.setDirection( dir );
this.setLength( length, headLength, headWidth );
setDirection( dir ) {
this.quaternion.set( 0, 0, 0, 1 );
this.quaternion.set( 1, 0, 0, 0 );
} else {
setColor( color ) {
this.line.material.color.set( color );
this.cone.material.color.set( color );
copy( source ) {
this.line.copy( source.line );
this.cone.copy( source.cone );
return this;
dispose() {
this.line.geometry.dispose();
this.line.material.dispose();
this.cone.geometry.dispose();
this.cone.material.dispose();
constructor( size = 1 ) {
const vertices = [
0, 0, 0, size, 0, 0,
0, 0, 0, 0, size, 0,
0, 0, 0, 0, 0, size
];
const colors = [
1, 0, 0, 1, 0.6, 0,
0, 1, 0, 0.6, 1, 0,
0, 0, 1, 0, 0.6, 1
];
this.type = 'AxesHelper';
color.set( xAxisColor );
color.toArray( array, 0 );
color.toArray( array, 3 );
color.set( yAxisColor );
color.toArray( array, 6 );
color.toArray( array, 9 );
color.set( zAxisColor );
color.toArray( array, 12 );
color.toArray( array, 15 );
this.geometry.attributes.color.needsUpdate = true;
return this;
dispose() {
this.geometry.dispose();
this.material.dispose();
class ShapePath {
constructor() {
this.type = 'ShapePath';
this.subPaths = [];
this.currentPath = null;
moveTo( x, y ) {
return this;
lineTo( x, y ) {
this.currentPath.lineTo( x, y );
return this;
return this;
return this;
splineThru( pts ) {
this.currentPath.splineThru( pts );
return this;
toShapes( isCCW ) {
shapes.push( tmpShape );
return shapes;
}
function isPointInsidePolygon( inPt, inPolygon ) {
// not parallel
if ( edgeDy < 0 ) {
} else {
} else {
// parallel or collinear
if ( inPt.y !== edgeLowPt.y ) continue;
// parallel
// edge lies on the same horizontal line as inPt
if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <=
edgeLowPt.x ) ) ||
( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <=
edgeHighPt.x ) ) ) return true; // inPt: Point on contour !
// continue;
return inside;
if ( subPaths.length === 1 ) {
tmpPath = subPaths[ 0 ];
tmpShape = new Shape();
tmpShape.curves = tmpPath.curves;
shapes.push( tmpShape );
return shapes;
tmpPath = subPaths[ i ];
tmpPoints = tmpPath.getPoints();
solid = isClockWise( tmpPoints );
solid = isCCW ? ! solid : solid;
if ( solid ) {
//console.log('cw', i);
} else {
//console.log('ccw', i);
if ( newShapes.length > 1 ) {
if ( isPointInsidePolygon( ho.p,
newShapes[ s2Idx ].p ) ) {
if ( hole_unassigned ) {
hole_unassigned = false;
} else {
ambiguous = true;
if ( hole_unassigned ) {
newShapeHoles = betterShapeHoles;
let tmpHoles;
//console.log("shape", shapes);
return shapes;
super();
this.object = object;
this.domElement = domElement;
this.enabled = true;
this.state = - 1;
this.keys = {};
this.mouseButtons = { LEFT: null, MIDDLE: null, RIGHT: null };
this.touches = { ONE: null, TWO: null };
connect() {}
disconnect() {}
dispose() {}
update( /* delta */ ) {}
texture.repeat.x = 1;
texture.repeat.y = imageAspect / aspect;
texture.offset.x = 0;
texture.offset.y = ( 1 - texture.repeat.y ) / 2;
} else {
texture.offset.x = ( 1 - texture.repeat.x ) / 2;
texture.offset.y = 0;
return texture;
texture.offset.x = ( 1 - texture.repeat.x ) / 2;
texture.offset.y = 0;
} else {
texture.repeat.x = 1;
texture.repeat.y = imageAspect / aspect;
texture.offset.x = 0;
texture.offset.y = ( 1 - texture.repeat.y ) / 2;
return texture;
texture.repeat.x = 1;
texture.repeat.y = 1;
texture.offset.x = 0;
texture.offset.y = 0;
return texture;
/**
* Given the width, height, format, and type of a texture. Determines how many
* bytes must be used to represent the texture.
*
* @param {Number} width
* @param {Number} height
* @param {Number} format
* @param {Number} type
* @return {Number} The number of bytes required to represent the texture.
*/
function getByteLength( width, height, format, type ) {
switch ( format ) {
//
https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml
case AlphaFormat:
return width * height;
case LuminanceFormat:
return width * height;
case LuminanceAlphaFormat:
return width * height * 2;
case RedFormat:
return ( ( width * height ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RedIntegerFormat:
return ( ( width * height ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RGFormat:
return ( ( width * height * 2 ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RGIntegerFormat:
return ( ( width * height * 2 ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RGBFormat:
return ( ( width * height * 3 ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RGBAFormat:
return ( ( width * height * 4 ) / typeByteLength.components ) *
typeByteLength.byteLength;
case RGBAIntegerFormat:
return ( ( width * height * 4 ) / typeByteLength.components ) *
typeByteLength.byteLength;
//
https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/
case RGB_S3TC_DXT1_Format:
case RGBA_S3TC_DXT1_Format:
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3
) / 4 ) * 8;
case RGBA_S3TC_DXT3_Format:
case RGBA_S3TC_DXT5_Format:
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3
) / 4 ) * 16;
//
https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/
case RGB_PVRTC_2BPPV1_Format:
case RGBA_PVRTC_2BPPV1_Format:
return ( Math.max( width, 16 ) * Math.max( height, 8 ) ) / 4;
case RGB_PVRTC_4BPPV1_Format:
case RGBA_PVRTC_4BPPV1_Format:
return ( Math.max( width, 8 ) * Math.max( height, 8 ) ) / 2;
//
https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/
case RGB_ETC1_Format:
case RGB_ETC2_Format:
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3
) / 4 ) * 8;
case RGBA_ETC2_EAC_Format:
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3
) / 4 ) * 16;
//
https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/
case RGBA_ASTC_4x4_Format:
return Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3
) / 4 ) * 16;
case RGBA_ASTC_5x4_Format:
return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 3
) / 4 ) * 16;
case RGBA_ASTC_5x5_Format:
return Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 4
) / 5 ) * 16;
case RGBA_ASTC_6x5_Format:
return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 4
) / 5 ) * 16;
case RGBA_ASTC_6x6_Format:
return Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 5
) / 6 ) * 16;
case RGBA_ASTC_8x5_Format:
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 4
) / 5 ) * 16;
case RGBA_ASTC_8x6_Format:
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 5
) / 6 ) * 16;
case RGBA_ASTC_8x8_Format:
return Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 7
) / 8 ) * 16;
case RGBA_ASTC_10x5_Format:
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height +
4 ) / 5 ) * 16;
case RGBA_ASTC_10x6_Format:
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height +
5 ) / 6 ) * 16;
case RGBA_ASTC_10x8_Format:
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height +
7 ) / 8 ) * 16;
case RGBA_ASTC_10x10_Format:
return Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height +
9 ) / 10 ) * 16;
case RGBA_ASTC_12x10_Format:
return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height +
9 ) / 10 ) * 16;
case RGBA_ASTC_12x12_Format:
return Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height +
11 ) / 12 ) * 16;
//
https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/
case RGBA_BPTC_Format:
case RGB_BPTC_SIGNED_Format:
case RGB_BPTC_UNSIGNED_Format:
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;
//
https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/
case RED_RGTC1_Format:
case SIGNED_RED_RGTC1_Format:
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 8;
case RED_GREEN_RGTC2_Format:
case SIGNED_RED_GREEN_RGTC2_Format:
return Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;
switch ( type ) {
case UnsignedByteType:
case ByteType:
return { byteLength: 1, components: 1 };
case UnsignedShortType:
case ShortType:
case HalfFloatType:
return { byteLength: 2, components: 1 };
case UnsignedShort4444Type:
case UnsignedShort5551Type:
return { byteLength: 2, components: 4 };
case UnsignedIntType:
case IntType:
case FloatType:
return { byteLength: 4, components: 1 };
case UnsignedInt5999Type:
return { byteLength: 4, components: 3 };
const TextureUtils = {
contain,
cover,
fill,
getByteLength
};
if ( window.__THREE__ ) {
} else {
window.__THREE__ = REVISION;
function WebGLAnimation() {
return {
start: function () {
isAnimating = true;
},
stop: function () {
context.cancelAnimationFrame( requestId );
isAnimating = false;
},
animationLoop = callback;
},
context = value;
};
function WebGLAttributes( gl ) {
attribute.onUploadCallback();
let type;
type = gl.FLOAT;
if ( attribute.isFloat16BufferAttribute ) {
type = gl.HALF_FLOAT;
} else {
type = gl.UNSIGNED_SHORT;
type = gl.SHORT;
type = gl.UNSIGNED_INT;
type = gl.INT;
type = gl.BYTE;
type = gl.UNSIGNED_BYTE;
type = gl.UNSIGNED_BYTE;
} else {
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version,
size: size
};
if ( updateRanges.length === 0 ) {
} else {
previousRange.count = Math.max(
previousRange.count,
range.start + range.count - previousRange.start
);
} else {
++ mergeIndex;
updateRanges[ mergeIndex ] = range;
attribute.clearUpdateRanges();
attribute.onUploadCallback();
//
if ( attribute.isInterleavedBufferAttribute ) attribute =
attribute.data;
if ( attribute.isInterleavedBufferAttribute ) attribute =
attribute.data;
if ( data ) {
gl.deleteBuffer( data.buffer );
buffers.delete( attribute );
}
}
if ( attribute.isInterleavedBufferAttribute ) attribute =
attribute.data;
if ( attribute.isGLBufferAttribute ) {
buffers.set( attribute, {
buffer: attribute.buffer,
type: attribute.type,
bytesPerElement: attribute.elementSize,
version: attribute.version
} );
return;
data.version = attribute.version;
return {
get: get,
remove: remove,
update: update
};
}
var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a <
getAlphaHashThreshold( vPosition ) ) discard;\n#endif";
const ShaderChunk = {
alphahash_fragment: alphahash_fragment,
alphahash_pars_fragment: alphahash_pars_fragment,
alphamap_fragment: alphamap_fragment,
alphamap_pars_fragment: alphamap_pars_fragment,
alphatest_fragment: alphatest_fragment,
alphatest_pars_fragment: alphatest_pars_fragment,
aomap_fragment: aomap_fragment,
aomap_pars_fragment: aomap_pars_fragment,
batching_pars_vertex: batching_pars_vertex,
batching_vertex: batching_vertex,
begin_vertex: begin_vertex,
beginnormal_vertex: beginnormal_vertex,
bsdfs: bsdfs,
iridescence_fragment: iridescence_fragment,
bumpmap_pars_fragment: bumpmap_pars_fragment,
clipping_planes_fragment: clipping_planes_fragment,
clipping_planes_pars_fragment: clipping_planes_pars_fragment,
clipping_planes_pars_vertex: clipping_planes_pars_vertex,
clipping_planes_vertex: clipping_planes_vertex,
color_fragment: color_fragment,
color_pars_fragment: color_pars_fragment,
color_pars_vertex: color_pars_vertex,
color_vertex: color_vertex,
common: common,
cube_uv_reflection_fragment: cube_uv_reflection_fragment,
defaultnormal_vertex: defaultnormal_vertex,
displacementmap_pars_vertex: displacementmap_pars_vertex,
displacementmap_vertex: displacementmap_vertex,
emissivemap_fragment: emissivemap_fragment,
emissivemap_pars_fragment: emissivemap_pars_fragment,
colorspace_fragment: colorspace_fragment,
colorspace_pars_fragment: colorspace_pars_fragment,
envmap_fragment: envmap_fragment,
envmap_common_pars_fragment: envmap_common_pars_fragment,
envmap_pars_fragment: envmap_pars_fragment,
envmap_pars_vertex: envmap_pars_vertex,
envmap_physical_pars_fragment: envmap_physical_pars_fragment,
envmap_vertex: envmap_vertex,
fog_vertex: fog_vertex,
fog_pars_vertex: fog_pars_vertex,
fog_fragment: fog_fragment,
fog_pars_fragment: fog_pars_fragment,
gradientmap_pars_fragment: gradientmap_pars_fragment,
lightmap_pars_fragment: lightmap_pars_fragment,
lights_lambert_fragment: lights_lambert_fragment,
lights_lambert_pars_fragment: lights_lambert_pars_fragment,
lights_pars_begin: lights_pars_begin,
lights_toon_fragment: lights_toon_fragment,
lights_toon_pars_fragment: lights_toon_pars_fragment,
lights_phong_fragment: lights_phong_fragment,
lights_phong_pars_fragment: lights_phong_pars_fragment,
lights_physical_fragment: lights_physical_fragment,
lights_physical_pars_fragment: lights_physical_pars_fragment,
lights_fragment_begin: lights_fragment_begin,
lights_fragment_maps: lights_fragment_maps,
lights_fragment_end: lights_fragment_end,
logdepthbuf_fragment: logdepthbuf_fragment,
logdepthbuf_pars_fragment: logdepthbuf_pars_fragment,
logdepthbuf_pars_vertex: logdepthbuf_pars_vertex,
logdepthbuf_vertex: logdepthbuf_vertex,
map_fragment: map_fragment,
map_pars_fragment: map_pars_fragment,
map_particle_fragment: map_particle_fragment,
map_particle_pars_fragment: map_particle_pars_fragment,
metalnessmap_fragment: metalnessmap_fragment,
metalnessmap_pars_fragment: metalnessmap_pars_fragment,
morphinstance_vertex: morphinstance_vertex,
morphcolor_vertex: morphcolor_vertex,
morphnormal_vertex: morphnormal_vertex,
morphtarget_pars_vertex: morphtarget_pars_vertex,
morphtarget_vertex: morphtarget_vertex,
normal_fragment_begin: normal_fragment_begin,
normal_fragment_maps: normal_fragment_maps,
normal_pars_fragment: normal_pars_fragment,
normal_pars_vertex: normal_pars_vertex,
normal_vertex: normal_vertex,
normalmap_pars_fragment: normalmap_pars_fragment,
clearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,
clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,
clearcoat_pars_fragment: clearcoat_pars_fragment,
iridescence_pars_fragment: iridescence_pars_fragment,
opaque_fragment: opaque_fragment,
packing: packing,
premultiplied_alpha_fragment: premultiplied_alpha_fragment,
project_vertex: project_vertex,
dithering_fragment: dithering_fragment,
dithering_pars_fragment: dithering_pars_fragment,
roughnessmap_fragment: roughnessmap_fragment,
roughnessmap_pars_fragment: roughnessmap_pars_fragment,
shadowmap_pars_fragment: shadowmap_pars_fragment,
shadowmap_pars_vertex: shadowmap_pars_vertex,
shadowmap_vertex: shadowmap_vertex,
shadowmask_pars_fragment: shadowmask_pars_fragment,
skinbase_vertex: skinbase_vertex,
skinning_pars_vertex: skinning_pars_vertex,
skinning_vertex: skinning_vertex,
skinnormal_vertex: skinnormal_vertex,
specularmap_fragment: specularmap_fragment,
specularmap_pars_fragment: specularmap_pars_fragment,
tonemapping_fragment: tonemapping_fragment,
tonemapping_pars_fragment: tonemapping_pars_fragment,
transmission_fragment: transmission_fragment,
transmission_pars_fragment: transmission_pars_fragment,
uv_pars_fragment: uv_pars_fragment,
uv_pars_vertex: uv_pars_vertex,
uv_vertex: uv_vertex,
worldpos_vertex: worldpos_vertex,
background_vert: vertex$h,
background_frag: fragment$h,
backgroundCube_vert: vertex$g,
backgroundCube_frag: fragment$g,
cube_vert: vertex$f,
cube_frag: fragment$f,
depth_vert: vertex$e,
depth_frag: fragment$e,
distanceRGBA_vert: vertex$d,
distanceRGBA_frag: fragment$d,
equirect_vert: vertex$c,
equirect_frag: fragment$c,
linedashed_vert: vertex$b,
linedashed_frag: fragment$b,
meshbasic_vert: vertex$a,
meshbasic_frag: fragment$a,
meshlambert_vert: vertex$9,
meshlambert_frag: fragment$9,
meshmatcap_vert: vertex$8,
meshmatcap_frag: fragment$8,
meshnormal_vert: vertex$7,
meshnormal_frag: fragment$7,
meshphong_vert: vertex$6,
meshphong_frag: fragment$6,
meshphysical_vert: vertex$5,
meshphysical_frag: fragment$5,
meshtoon_vert: vertex$4,
meshtoon_frag: fragment$4,
points_vert: vertex$3,
points_frag: fragment$3,
shadow_vert: vertex$2,
shadow_frag: fragment$2,
sprite_vert: vertex$1,
sprite_frag: fragment$1
};
/**
* Uniforms library for shared webgl shaders
*/
const UniformsLib = {
common: {
alphaTest: { value: 0 }
},
specularmap: {
},
envmap: {
},
aomap: {
},
lightmap: {
lightMap: { value: null },
lightMapIntensity: { value: 1 },
lightMapTransform: { value: /*@__PURE__*/ new Matrix3() }
},
bumpmap: {
},
normalmap: {
},
displacementmap: {
},
emissivemap: {
},
metalnessmap: {
},
roughnessmap: {
},
gradientmap: {
},
fog: {
fogDensity: { value: 0.00025 },
fogNear: { value: 1 },
fogFar: { value: 2000 },
fogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }
},
lights: {
ambientLightColor: { value: [] },
lightProbe: { value: [] },
directionalShadowMap: { value: [] },
directionalShadowMatrix: { value: [] },
spotLightMap: { value: [] },
spotShadowMap: { value: [] },
spotLightMatrix: { value: [] },
pointShadowMap: { value: [] },
pointShadowMatrix: { value: [] },
},
points: {
},
sprite: {
};
const ShaderLib = {
basic: {
vertexShader: ShaderChunk.meshbasic_vert,
fragmentShader: ShaderChunk.meshbasic_frag
},
lambert: {
vertexShader: ShaderChunk.meshlambert_vert,
fragmentShader: ShaderChunk.meshlambert_frag
},
phong: {
vertexShader: ShaderChunk.meshphong_vert,
fragmentShader: ShaderChunk.meshphong_frag
},
standard: {
vertexShader: ShaderChunk.meshphysical_vert,
fragmentShader: ShaderChunk.meshphysical_frag
},
toon: {
},
matcap: {
vertexShader: ShaderChunk.meshmatcap_vert,
fragmentShader: ShaderChunk.meshmatcap_frag
},
points: {
vertexShader: ShaderChunk.points_vert,
fragmentShader: ShaderChunk.points_frag
},
dashed: {
vertexShader: ShaderChunk.linedashed_vert,
fragmentShader: ShaderChunk.linedashed_frag
},
depth: {
},
normal: {
vertexShader: ShaderChunk.meshnormal_vert,
fragmentShader: ShaderChunk.meshnormal_frag
},
sprite: {
vertexShader: ShaderChunk.sprite_vert,
fragmentShader: ShaderChunk.sprite_frag
},
background: {
uniforms: {
uvTransform: { value: /*@__PURE__*/ new Matrix3() },
t2D: { value: null },
backgroundIntensity: { value: 1 }
},
vertexShader: ShaderChunk.background_vert,
fragmentShader: ShaderChunk.background_frag
},
backgroundCube: {
uniforms: {
envMap: { value: null },
flipEnvMap: { value: - 1 },
backgroundBlurriness: { value: 0 },
backgroundIntensity: { value: 1 },
backgroundRotation: { value: /*@__PURE__*/ new Matrix3() }
},
vertexShader: ShaderChunk.backgroundCube_vert,
fragmentShader: ShaderChunk.backgroundCube_frag
},
cube: {
uniforms: {
tCube: { value: null },
tFlip: { value: - 1 },
opacity: { value: 1.0 }
},
vertexShader: ShaderChunk.cube_vert,
fragmentShader: ShaderChunk.cube_frag
},
equirect: {
uniforms: {
tEquirect: { value: null },
},
vertexShader: ShaderChunk.equirect_vert,
fragmentShader: ShaderChunk.equirect_frag
},
distanceRGBA: {
vertexShader: ShaderChunk.distanceRGBA_vert,
fragmentShader: ShaderChunk.distanceRGBA_frag
},
shadow: {
vertexShader: ShaderChunk.shadow_vert,
fragmentShader: ShaderChunk.shadow_frag
}
};
ShaderLib.physical = {
vertexShader: ShaderChunk.meshphysical_vert,
fragmentShader: ShaderChunk.meshphysical_frag
};
const _rgb = { r: 0, b: 0, g: 0 };
const _e1$1 = /*@__PURE__*/ new Euler();
const _m1$1 = /*@__PURE__*/ new Matrix4();
let planeMesh;
let boxMesh;
return background;
setClear( background, 1 );
forceClear = true;
state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );
state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );
if ( renderer.autoClear || forceClear ) {
state.buffers.depth.setTest( true );
state.buffers.depth.setMask( true );
state.buffers.color.setMask( true );
boxMesh.geometry.deleteAttribute( 'normal' );
boxMesh.geometry.deleteAttribute( 'uv' );
};
get: function () {
return this.uniforms.envMap.value;
} );
objects.update( boxMesh );
_e1$1.copy( scene.backgroundRotation );
boxMesh.material.uniforms.envMap.value = background;
boxMesh.material.uniforms.flipEnvMap.value =
( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 :
1;
boxMesh.material.uniforms.backgroundBlurriness.value =
scene.backgroundBlurriness;
boxMesh.material.uniforms.backgroundIntensity.value =
scene.backgroundIntensity;
boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotati
onFromEuler( _e1$1 ) );
boxMesh.material.toneMapped =
ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
boxMesh.material.needsUpdate = true;
currentBackground = background;
currentBackgroundVersion = background.version;
currentTonemapping = renderer.toneMapping;
}
boxMesh.layers.enableAll();
planeMesh.geometry.deleteAttribute( 'normal' );
get: function () {
return this.uniforms.t2D.value;
} );
objects.update( planeMesh );
planeMesh.material.uniforms.t2D.value = background;
planeMesh.material.uniforms.backgroundIntensity.value =
scene.backgroundIntensity;
planeMesh.material.toneMapped =
ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;
background.updateMatrix();
}
planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );
planeMesh.material.needsUpdate = true;
currentBackground = background;
currentBackgroundVersion = background.version;
currentTonemapping = renderer.toneMapping;
planeMesh.layers.enableAll();
function dispose() {
boxMesh.geometry.dispose();
boxMesh.material.dispose();
boxMesh = undefined;
planeMesh.geometry.dispose();
planeMesh.material.dispose();
planeMesh = undefined;
return {
getClearColor: function () {
return clearColor;
},
setClearColor: function ( color, alpha = 1 ) {
clearColor.set( color );
clearAlpha = alpha;
setClear( clearColor, clearAlpha );
},
getClearAlpha: function () {
return clearAlpha;
},
setClearAlpha: function ( alpha ) {
clearAlpha = alpha;
setClear( clearColor, clearAlpha );
},
render: render,
addToRenderList: addToRenderList,
dispose: dispose
};
currentState = state;
bindVertexArrayObject( currentState.object );
if ( updateBuffers || forceUpdate ) {
forceUpdate = false;
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER,
attributes.get( index ).buffer );
function createVertexArrayObject() {
return gl.createVertexArray();
programMap = {};
bindingStates[ geometry.id ] = programMap;
stateMap = {};
programMap[ program.id ] = stateMap;
}
return state;
newAttributes[ i ] = 0;
enabledAttributes[ i ] = 0;
attributeDivisors[ i ] = 0;
return {
newAttributes: newAttributes,
enabledAttributes: enabledAttributes,
attributeDivisors: attributeDivisors,
object: vao,
attributes: {},
index: null
};
let attributesNum = 0;
if ( programAttribute.location >= 0 ) {
attributesNum ++;
return false;
if ( programAttribute.location >= 0 ) {
data.data = attribute.data;
attributesNum ++;
currentState.attributes = cache;
currentState.attributesNum = attributesNum;
currentState.index = index;
function initAttributes() {
newAttributes[ i ] = 0;
enableAttributeAndDivisor( attribute, 0 );
newAttributes[ attribute ] = 1;
gl.enableVertexAttribArray( attribute );
enabledAttributes[ attribute ] = 1;
}
function disableUnusedAttributes() {
gl.disableVertexAttribArray( i );
enabledAttributes[ i ] = 0;
} else {
initAttributes();
const attribute =
attributes.get( geometryAttribute );
if ( geometryAttribute.isInterleavedBufferAttribute )
{
if ( data.isInstancedInterleavedBuffer ) {
enableAttributeAndDivisor( programAttribute.location + i,
data.meshPerAttribute );
geometry._maxInstanceCount =
data.meshPerAttribute * data.count;
}
} else {
enableAttribute( programAttribute.location + i );
vertexAttribPointer(
programAttribute.location + i,
size /
programAttribute.locationSize,
type,
normalized,
stride * bytesPerElement,
( offset + ( size /
programAttribute.locationSize ) * i ) * bytesPerElement,
integer
);
} else {
if
( geometryAttribute.isInstancedBufferAttribute ) {
enableAttributeAndDivisor( programAttribute.location + i,
geometryAttribute.meshPerAttribute );
geometry._maxInstanceCount =
geometryAttribute.meshPerAttribute * geometryAttribute.count;
} else {
vertexAttribPointer(
programAttribute.location + i,
size /
programAttribute.locationSize,
type,
normalized,
size * bytesPerElement,
( size /
programAttribute.locationSize ) * i * bytesPerElement,
integer
);
switch ( value.length ) {
case 2:
case 3:
case 4:
default:
}
}
disableUnusedAttributes();
function dispose() {
reset();
function reset() {
resetDefaultState();
forceUpdate = true;
currentState = defaultState;
bindVertexArrayObject( currentState.object );
// for backward-compatibility
function resetDefaultState() {
defaultState.geometry = null;
defaultState.program = null;
defaultState.wireframe = false;
return {
setup: setup,
reset: reset,
resetDefaultState: resetDefaultState,
dispose: dispose,
releaseStatesOfGeometry: releaseStatesOfGeometry,
releaseStatesOfProgram: releaseStatesOfProgram,
initAttributes: initAttributes,
enableAttribute: enableAttribute,
disableUnusedAttributes: disableUnusedAttributes
};
let mode;
mode = value;
let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {
elementCount += counts[ i ];
} else {
let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {
//
this.setMode = setMode;
this.render = render;
this.renderInstances = renderInstances;
this.renderMultiDraw = renderMultiDraw;
this.renderMultiDrawInstances = renderMultiDrawInstances;
let maxAnisotropy;
function getMaxAnisotropy() {
const extension =
extensions.get( 'EXT_texture_filter_anisotropic' );
maxAnisotropy =
gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );
} else {
maxAnisotropy = 0;
return maxAnisotropy;
return false;
return true;
return false;
return true;
return 'highp';
precision = 'mediump';
}
if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER,
gl.MEDIUM_FLOAT ).precision > 0 &&
gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER,
gl.MEDIUM_FLOAT ).precision > 0 ) {
return 'mediump';
return 'lowp';
return {
getMaxAnisotropy: getMaxAnisotropy,
getMaxPrecision: getMaxPrecision,
textureFormatReadable: textureFormatReadable,
textureTypeReadable: textureTypeReadable,
precision: precision,
logarithmicDepthBuffer: logarithmicDepthBuffer,
reverseDepthBuffer: reverseDepthBuffer,
maxTextures: maxTextures,
maxVertexTextures: maxVertexTextures,
maxTextureSize: maxTextureSize,
maxCubemapSize: maxCubemapSize,
maxAttributes: maxAttributes,
maxVertexUniforms: maxVertexUniforms,
maxVaryings: maxVaryings,
maxFragmentUniforms: maxFragmentUniforms,
vertexTextures: vertexTextures,
maxSamples: maxSamples
};
this.uniform = uniform;
this.numPlanes = 0;
this.numIntersection = 0;
const enabled =
planes.length !== 0 ||
enableLocalClipping ||
// enable state of previous frame - the clipping code has to
// run another frame in order to reset the state:
numGlobalPlanes !== 0 ||
localClippingEnabled;
localClippingEnabled = enableLocalClipping;
numGlobalPlanes = planes.length;
return enabled;
};
this.beginShadows = function () {
renderingShadows = true;
projectPlanes( null );
};
this.endShadows = function () {
renderingShadows = false;
};
};
if ( renderingShadows ) {
projectPlanes( null );
} else {
resetGlobalState();
} else {
dstArray[ i ] = globalState[ i ];
}
materialProperties.clippingState = dstArray;
this.numIntersection = clipIntersection ? this.numPlanes : 0;
this.numPlanes += nGlobal;
};
function resetGlobalState() {
uniform.value = globalState;
uniform.needsUpdate = numGlobalPlanes > 0;
scope.numPlanes = numGlobalPlanes;
scope.numIntersection = 0;
if ( nPlanes !== 0 ) {
dstArray = uniform.value;
viewNormalMatrix.getNormalMatrix( viewMatrix );
plane.normal.toArray( dstArray, i4 );
dstArray[ i4 + 3 ] = plane.constant;
}
}
uniform.value = dstArray;
uniform.needsUpdate = true;
scope.numPlanes = nPlanes;
scope.numIntersection = 0;
return dstArray;
texture.mapping = CubeReflectionMapping;
texture.mapping = CubeRefractionMapping;
return texture;
if ( cubemaps.has( texture ) ) {
} else {
texture.addEventListener( 'dispose',
onTextureDispose );
} else {
return null;
return texture;
cubemaps.delete( texture );
cubemap.dispose();
function dispose() {
return {
get: get,
dispose: dispose
};
const LOD_MIN = 4;
// The standard deviations (radians) associated with the extra mips. These are
// chosen to approximate a Trowbridge-Reitz distribution function times the
// geometric shadowing function. These sigma values squared must match the
// variance #defines in cube_uv_reflection_fragment.glsl.js.
const EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];
// The maximum length of the blur for loop. Smaller sigmas will use fewer
// samples and exit early, but not recompile the shader.
const MAX_SAMPLES = 20;
// Golden Ratio
const PHI = ( 1 + Math.sqrt( 5 ) ) / 2;
const INV_PHI = 1 / PHI;
/**
* This class generates a Prefiltered, Mipmapped Radiance Environment Map
* (PMREM) from a cubeMap environment texture. This allows different levels of
* blur to be quickly accessed based on material roughness. It is packed into a
* special CubeUV format that allows us to perform custom interpolation so that
* we can support nonlinear formats such as RGBE. Unlike a traditional mipmap
* chain, it only goes down to the LOD_MIN level (above), and then creates extra
* even more filtered 'mips' at the same LOD_MIN resolution, associated with
* higher roughness levels. In this way we maintain resolution to smoothly
* interpolate diffuse lighting while limiting sampling computation.
*
* Paper: Fast, Accurate Image-Based Lighting
* https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view
*/
class PMREMGenerator {
constructor( renderer ) {
this._renderer = renderer;
this._pingPongRenderTarget = null;
this._lodMax = 0;
this._cubeSize = 0;
this._lodPlanes = [];
this._sizeLods = [];
this._sigmas = [];
this._blurMaterial = null;
this._cubemapMaterial = null;
this._equirectMaterial = null;
this._compileMaterial( this._blurMaterial );
/**
* Generates a PMREM from a supplied Scene, which can be faster than using an
* image if networking bandwidth is low. Optional sigma specifies a blur
radius
* in radians to be applied to the scene before PMREM generation. Optional
near
* and far planes ensure the scene is rendered in its entirety (the
cubeCamera
* is placed at the origin).
*
* @param {Scene} scene
* @param {number} sigma
* @param {number} near
* @param {number} far
* @return {WebGLRenderTarget}
*/
fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
_oldTarget = this._renderer.getRenderTarget();
_oldActiveCubeFace = this._renderer.getActiveCubeFace();
_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
_oldXrEnabled = this._renderer.xr.enabled;
this._renderer.xr.enabled = false;
this._setSize( 256 );
if ( sigma > 0 ) {
this._applyPMREM( cubeUVRenderTarget );
this._cleanup( cubeUVRenderTarget );
return cubeUVRenderTarget;
/**
* Generates a PMREM from an equirectangular texture, which can be either LDR
* or HDR. The ideal input image size is 1k (1024 x 512),
* as this matches best with the 256 x 256 cubemap output.
* The smallest supported equirectangular image size is 64 x 32.
*
* @param {Texture} equirectangular
* @param {WebGLRenderTarget} [renderTarget=null] - Optional render target.
* @return {WebGLRenderTarget}
*/
fromEquirectangular( equirectangular, renderTarget = null ) {
/**
* Generates a PMREM from an cubemap texture, which can be either LDR
* or HDR. The ideal input cube size is 256 x 256,
* as this matches best with the 256 x 256 cubemap output.
* The smallest supported cube size is 16 x 16.
*
* @param {Texture} cubemap
* @param {null} [renderTarget=null] - Optional render target.
* @return {WebGLRenderTarget}
*/
fromCubemap( cubemap, renderTarget = null ) {
/**
* Pre-compiles the cubemap shader. You can get faster start-up by invoking
this method during
* your texture's network fetch for increased concurrency.
*/
compileCubemapShader() {
this._cubemapMaterial = _getCubemapMaterial();
this._compileMaterial( this._cubemapMaterial );
/**
* Pre-compiles the equirectangular shader. You can get faster start-up by
invoking this method during
* your texture's network fetch for increased concurrency.
*/
compileEquirectangularShader() {
this._equirectMaterial = _getEquirectMaterial();
this._compileMaterial( this._equirectMaterial );
}
/**
* Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator
is a static class,
* so you should not need more than one PMREMGenerator object. If you do,
calling dispose() on
* one of them will cause any others to also become unusable.
*/
dispose() {
this._dispose();
// private interface
_setSize( cubeSize ) {
_dispose() {
this._lodPlanes[ i ].dispose();
_cleanup( outputTarget ) {
outputTarget.scissorTest = false;
_setViewport( outputTarget, 0, 0, outputTarget.width,
outputTarget.height );
} else { // Equirectangular
this._setSize( texture.image.width / 4 );
_oldTarget = this._renderer.getRenderTarget();
_oldActiveCubeFace = this._renderer.getActiveCubeFace();
_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
_oldXrEnabled = this._renderer.xr.enabled;
this._renderer.xr.enabled = false;
return cubeUVRenderTarget;
_allocateTargets() {
const params = {
magFilter: LinearFilter,
minFilter: LinearFilter,
generateMipmaps: false,
type: HalfFloatType,
format: RGBAFormat,
colorSpace: LinearSRGBColorSpace,
depthBuffer: false
};
this._dispose();
return cubeUVRenderTarget;
_compileMaterial( material ) {
renderer.toneMapping = NoToneMapping;
renderer.autoClear = false;
if ( background ) {
if ( background.isColor ) {
backgroundMaterial.color.copy( background );
scene.background = null;
useSolidColor = true;
} else {
backgroundMaterial.color.copy( _clearColor );
useSolidColor = true;
const col = i % 3;
if ( col === 0 ) {
cubeCamera.up.set( 0, upSign[ i ], 0 );
cubeCamera.lookAt( forwardSign[ i ], 0, 0 );
cubeCamera.up.set( 0, 0, upSign[ i ] );
cubeCamera.lookAt( 0, forwardSign[ i ], 0 );
} else {
cubeCamera.up.set( 0, upSign[ i ], 0 );
cubeCamera.lookAt( 0, 0, forwardSign[ i ] );
renderer.setRenderTarget( cubeUVRenderTarget );
if ( useSolidColor ) {
backgroundBox.geometry.dispose();
backgroundBox.material.dispose();
renderer.toneMapping = toneMapping;
renderer.autoClear = originalAutoClear;
scene.background = background;
this._cubemapMaterial = _getCubemapMaterial();
this._cubemapMaterial.uniforms.flipEnvMap.value =
( texture.isRenderTargetTexture === false ) ? - 1 : 1;
} else {
this._equirectMaterial = _getEquirectMaterial();
renderer.setRenderTarget( cubeUVRenderTarget );
renderer.render( mesh, _flatCamera );
_applyPMREM( cubeUVRenderTarget ) {
renderer.autoClear = autoClear;
}
/**
* This is a two-pass Gaussian blur for a cubemap. Normally this is done
* vertically and horizontally, but this breaks down on a cube. Here we apply
* the blur latitudinally (around the poles), and then longitudinally
(towards
* the poles) to approximate the orthogonally-separable blur. It is least
* accurate at the poles, but still does a decent job.
*
* @param {WebGLRenderTarget} cubeUVRenderTarget
* @param {number} lodIn
* @param {number} lodOut
* @param {number} sigma
* @param {Vector3} [poleAxis]
*/
_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
this._halfBlur(
cubeUVRenderTarget,
pingPongRenderTarget,
lodIn,
lodOut,
sigma,
'latitudinal',
poleAxis );
this._halfBlur(
pingPongRenderTarget,
cubeUVRenderTarget,
lodOut,
lodOut,
sigma,
'longitudinal',
poleAxis );
console.error(
'blur direction must be either latitudinal or
longitudinal!' );
console.warn( `sigmaRadians, ${
sigmaRadians}, is too large and will clip, as it requested
${
samples} samples when the maximum is set to ${MAX_SAMPLES}`
);
const x = i / sigmaPixels;
const weight = Math.exp( - x * x / 2 );
weights.push( weight );
if ( i === 0 ) {
sum += weight;
sum += 2 * weight;
if ( poleAxis ) {
} else if ( i === 0 ) {
sigma = 0;
sigmas.push( sigma );
const cubeFaces = 6;
const vertices = 6;
const positionSize = 3;
const uvSize = 2;
const faceIndexSize = 1;
const position = new Float32Array( positionSize * vertices *
cubeFaces );
const uv = new Float32Array( uvSize * vertices * cubeFaces );
const faceIndex = new Float32Array( faceIndexSize * vertices *
cubeFaces );
const x = ( face % 3 ) * 2 / 3 - 1;
const y = face > 2 ? 0 : - 1;
const coordinates = [
x, y, 0,
x + 2 / 3, y, 0,
x + 2 / 3, y + 1, 0,
x, y, 0,
x + 2 / 3, y + 1, 0,
x, y + 1, 0
];
position.set( coordinates, positionSize * vertices * face );
uv.set( uv1, uvSize * vertices * face );
const fill = [ face, face, face, face, face, face ];
faceIndex.set( fill, faceIndexSize * vertices * face );
lod --;
name: 'SphericalGaussianBlur',
defines: {
'n': MAX_SAMPLES,
'CUBEUV_TEXEL_WIDTH': 1.0 / width,
'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
'CUBEUV_MAX_MIP': `${lodMax}.0`,
},
uniforms: {
'envMap': { value: null },
'samples': { value: 1 },
'weights': { value: weights },
'latitudinal': { value: false },
'dTheta': { value: 0 },
'mipInt': { value: 0 },
'poleAxis': { value: poleAxis }
},
vertexShader: _getCommonVertexShader(),
#define ENVMAP_TYPE_CUBE_UV
#include <cube_uv_reflection_fragment>
void main() {
if ( i >= samples ) {
break;
}
`,
blending: NoBlending,
depthTest: false,
depthWrite: false
} );
return shaderMaterial;
function _getEquirectMaterial() {
name: 'EquirectangularToCubeUV',
uniforms: {
'envMap': { value: null }
},
vertexShader: _getCommonVertexShader(),
fragmentShader: /* glsl */`
#include <common>
void main() {
}
`,
blending: NoBlending,
depthTest: false,
depthWrite: false
} );
function _getCubemapMaterial() {
name: 'CubemapToCubeUV',
uniforms: {
'envMap': { value: null },
'flipEnvMap': { value: - 1 }
},
vertexShader: _getCommonVertexShader(),
void main() {
blending: NoBlending,
depthTest: false,
depthWrite: false
} );
function _getCommonVertexShader() {
uv = 2.0 * uv - 1.0;
if ( face == 0.0 ) {
direction = direction.xzy;
direction.xz *= -1.0; // ( -u, 1, -v ) pos y
direction = direction.zyx;
direction.xz *= -1.0; // ( -1, v, -u ) neg x
direction = direction.xzy;
direction.xy *= -1.0; // ( -u, -1, v ) neg y
return direction;
}
void main() {
}
`;
if ( isEquirectMap || isCubeMap ) {
if ( texture.isRenderTargetTexture &&
texture.pmremVersion !== currentPMREMVersion ) {
renderTarget = isEquirectMap ?
pmremGenerator.fromEquirectangular( texture, renderTarget ) :
pmremGenerator.fromCubemap( texture, renderTarget );
renderTarget.texture.pmremVersion =
texture.pmremVersion;
return renderTarget.texture;
} else {
} else {
renderTarget = isEquirectMap ?
pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture
);
renderTarget.texture.pmremVersion =
texture.pmremVersion;
texture.addEventListener( 'dispose',
onTextureDispose );
return renderTarget.texture;
} else {
return null;
return texture;
let count = 0;
const length = 6;
cubeUVmaps.delete( texture );
cubemapUV.dispose();
function dispose() {
pmremGenerator.dispose();
pmremGenerator = null;
return {
get: get,
dispose: dispose
};
function WebGLExtensions( gl ) {
let extension;
switch ( name ) {
case 'WEBGL_depth_texture':
extension = gl.getExtension( 'WEBGL_depth_texture' ) ||
gl.getExtension( 'MOZ_WEBGL_depth_texture' ) ||
gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
break;
case 'EXT_texture_filter_anisotropic':
extension =
gl.getExtension( 'EXT_texture_filter_anisotropic' ) ||
gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) ||
gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
break;
case 'WEBGL_compressed_texture_s3tc':
extension =
gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) ||
gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) ||
gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
break;
case 'WEBGL_compressed_texture_pvrtc':
extension =
gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) ||
gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
break;
default:
extension = gl.getExtension( name );
return extension;
return {
},
init: function () {
getExtension( 'EXT_color_buffer_float' );
getExtension( 'WEBGL_clip_cull_distance' );
getExtension( 'OES_texture_float_linear' );
getExtension( 'EXT_color_buffer_half_float' );
getExtension( 'WEBGL_multisampled_render_to_texture' );
getExtension( 'WEBGL_render_shared_exponent' );
},
return extension;
};
attributes.remove( geometry.index );
if ( attribute ) {
attributes.remove( attribute );
wireframeAttributes.delete( geometry );
bindingStates.releaseStatesOfGeometry( geometry );
delete geometry._maxInstanceCount;
//
info.memory.geometries --;
}
info.memory.geometries ++;
return geometry;
const a = array[ i + 0 ];
const b = array[ i + 1 ];
const c = array[ i + 2 ];
indices.push( a, b, b, c, c, a );
indices.push( a, b, b, c, c, a );
} else {
return;
//
//
if ( currentAttribute ) {
updateWireframeAttribute( geometry );
} else {
updateWireframeAttribute( geometry );
}
return wireframeAttributes.get( geometry );
return {
get: get,
update: update,
getWireframeAttribute: getWireframeAttribute
};
let mode;
mode = value;
type = value.type;
bytesPerElement = value.bytesPerElement;
let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {
elementCount += counts[ i ];
} else {
let elementCount = 0;
for ( let i = 0; i < drawCount; i ++ ) {
//
this.setMode = setMode;
this.setIndex = setIndex;
this.render = render;
this.renderInstances = renderInstances;
this.renderMultiDraw = renderMultiDraw;
this.renderMultiDrawInstances = renderMultiDrawInstances;
}
function WebGLInfo( gl ) {
const memory = {
geometries: 0,
textures: 0
};
const render = {
frame: 0,
calls: 0,
triangles: 0,
points: 0,
lines: 0
};
render.calls ++;
switch ( mode ) {
case gl.TRIANGLES:
render.triangles += instanceCount * ( count / 3 );
break;
case gl.LINES:
render.lines += instanceCount * ( count / 2 );
break;
case gl.LINE_STRIP:
render.lines += instanceCount * ( count - 1 );
break;
case gl.LINE_LOOP:
render.lines += instanceCount * count;
break;
case gl.POINTS:
render.points += instanceCount * count;
break;
default:
console.error( 'THREE.WebGLInfo: Unknown draw mode:',
mode );
break;
function reset() {
render.calls = 0;
render.triangles = 0;
render.points = 0;
render.lines = 0;
}
return {
memory: memory,
render: render,
programs: null,
autoReset: true,
reset: reset,
update: update
};
let vertexDataCount = 0;
// fill buffer
morph.fromBufferAttribute( morphTarget, j );
morph.fromBufferAttribute( morphNormal, j );
morph.fromBufferAttribute( morphColor, j );
}
}
entry = {
count: morphTargetsCount,
texture: texture,
size: new Vector2( width, height )
};
function disposeTexture() {
texture.dispose();
morphTextures.delete( geometry );
//
if ( object.isInstancedMesh === true && object.morphTexture !== null )
{
} else {
let morphInfluencesSum = 0;
morphInfluencesSum += objectInfluences[ i ];
return {
update: update
};
geometries.update( buffergeometry );
if ( object.isInstancedMesh ) {
object.addEventListener( 'dispose',
onInstancedMeshDispose );
attributes.update( object.instanceMatrix,
gl.ARRAY_BUFFER );
attributes.update( object.instanceColor,
gl.ARRAY_BUFFER );
}
if ( object.isSkinnedMesh ) {
skeleton.update();
return buffergeometry;
function dispose() {
attributes.remove( instancedMesh.instanceMatrix );
return {
update: update,
dispose: dispose
};
/**
* Uniforms of a program.
* Those form a tree structure with a special top-level container for the root,
* which you get by calling 'new WebGLUniforms( gl, program )'.
*
*
* Properties of inner nodes including the top-level container:
*
* .seq - array of nested uniforms
* .map - nested uniforms by name
*
*
* Methods of all nodes except the top-level container:
*
* .setValue( gl, value, [textures] )
*
* uploads a uniform value(s)
* the 'textures' parameter is needed for sampler uniforms
*
*
* Static methods of the top-level container (textures factorizations):
*
* .upload( gl, seq, values, textures )
*
* sets uniforms in 'seq' to 'values[id].value'
*
* .seqWithValue( seq, values ) : filteredSeq
*
* filters 'seq' entries with corresponding entry in values
*
*
* Methods of the top-level container (textures factorizations):
*
* .setValue( gl, name, value, textures )
*
* sets uniform with name 'name' to 'value'
*
* .setOptional( gl, obj, prop )
*
* like .set for an optional property of the object
*
*/
if ( r === undefined ) {
r = new Float32Array( n );
arrayCacheF32[ n ] = r;
if ( nBlocks !== 0 ) {
firstElem.toArray( r, 0 );
offset += blockSize;
array[ i ].toArray( r, offset );
return r;
function arraysEqual( a, b ) {
return true;
function copyArray( a, b ) {
a[ i ] = b[ i ];
if ( r === undefined ) {
r = new Int32Array( n );
arrayCacheI32[ n ] = r;
r[ i ] = textures.allocateTextureUnit();
return r;
// Single scalar
gl.uniform1f( this.addr, v );
cache[ 0 ] = v;
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
} else {
copyArray( cache, v );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
cache[ 0 ] = v.r;
cache[ 1 ] = v.g;
cache[ 2 ] = v.b;
} else {
gl.uniform3fv( this.addr, v );
copyArray( cache, v );
} else {
gl.uniform4fv( this.addr, v );
copyArray( cache, v );
copyArray( cache, v );
} else {
mat2array.set( elements );
} else {
mat3array.set( elements );
copyArray( cache, v );
} else {
mat4array.set( elements );
gl.uniform1i( this.addr, v );
cache[ 0 ] = v;
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
} else {
gl.uniform2iv( this.addr, v );
copyArray( cache, v );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
} else {
gl.uniform3iv( this.addr, v );
copyArray( cache, v );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
cache[ 3 ] = v.w;
} else {
gl.uniform4iv( this.addr, v );
copyArray( cache, v );
gl.uniform1ui( this.addr, v );
cache[ 0 ] = v;
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
} else {
if ( arraysEqual( cache, v ) ) return;
gl.uniform2uiv( this.addr, v );
copyArray( cache, v );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
} else {
gl.uniform3uiv( this.addr, v );
copyArray( cache, v );
cache[ 0 ] = v.x;
cache[ 1 ] = v.y;
cache[ 2 ] = v.z;
cache[ 3 ] = v.w;
} else {
copyArray( cache, v );
let emptyTexture2D;
} else {
emptyTexture2D = emptyTexture;
switch ( type ) {
// Array of scalars
gl.uniform1fv( this.addr, v );
}
// Array of matrices (from flat array or array of THREE.MatrixN)
gl.uniform1iv( this.addr, v );
gl.uniform2iv( this.addr, v );
gl.uniform3iv( this.addr, v );
gl.uniform4iv( this.addr, v );
gl.uniform1uiv( this.addr, v );
}
gl.uniform2uiv( this.addr, v );
gl.uniform3uiv( this.addr, v );
gl.uniform4uiv( this.addr, v );
const n = v.length;
const n = v.length;
const n = v.length;
const n = v.length;
switch ( type ) {
this.id = id;
this.addr = addr;
this.cache = [];
this.type = activeInfo.type;
this.setValue = getSingularSetter( activeInfo.type );
class PureArrayUniform {
this.id = id;
this.addr = addr;
this.cache = [];
this.type = activeInfo.type;
this.size = activeInfo.size;
this.setValue = getPureArraySetter( activeInfo.type );
class StructuredUniform {
constructor( id ) {
this.id = id;
this.seq = [];
this.map = {};
const u = seq[ i ];
u.setValue( gl, value[ u.id ], textures );
}
// --- Top-level ---
// extracts
// - the identifier (member name or array index)
// - followed by an optional right bracket (found when array index)
// - followed by an optional left bracket or dot (type of subscript)
//
// Note: These portions can be read in a non-overlapping fashion and
// allow straightforward parsing of the hierarchy that WebGL encodes
// in the uniform names.
container.seq.push( uniformObject );
container.map[ uniformObject.id ] = uniformObject;
while ( true ) {
let id = match[ 1 ];
const idIsIndex = match[ 2 ] === ']',
subscript = match[ 3 ];
break;
} else {
container = next;
// Root Container
class WebGLUniforms {
this.seq = [];
this.map = {};
const u = seq[ i ],
v = values[ u.id ];
const r = [];
const u = seq[ i ];
if ( u.id in values ) r.push( u );
return r;
return shader;
// From
https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/
const COMPLETION_STATUS_KHR = 0x91B1;
let programIdCount = 0;
const line = i + 1;
lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}`
);
case LinearTransfer:
return [ encodingMatrix, 'LinearTransferOETF' ];
case SRGBTransfer:
return [ encodingMatrix, 'sRGBTransferOETF' ];
default:
console.warn( 'THREE.WebGLProgram: Unsupported color space: ',
colorSpace );
return [ encodingMatrix, 'LinearTransferOETF' ];
// --enable-privileged-webgl-extension
// console.log( '**' + type + '**',
gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );
} else {
return errors;
}
}
return [
'}',
].join( '\n' );
let toneMappingName;
switch ( toneMapping ) {
case LinearToneMapping:
toneMappingName = 'Linear';
break;
case ReinhardToneMapping:
toneMappingName = 'Reinhard';
break;
case CineonToneMapping:
toneMappingName = 'Cineon';
break;
case ACESFilmicToneMapping:
toneMappingName = 'ACESFilmic';
break;
case AgXToneMapping:
toneMappingName = 'AgX';
break;
case NeutralToneMapping:
toneMappingName = 'Neutral';
break;
case CustomToneMapping:
toneMappingName = 'Custom';
break;
default:
console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:',
toneMapping );
toneMappingName = 'Linear';
}
return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName
+ 'ToneMapping( color ); }';
function getLuminanceFunction() {
ColorManagement.getLuminanceCoefficients( _v0 );
const r = _v0.x.toFixed( 4 );
const g = _v0.y.toFixed( 4 );
const b = _v0.z.toFixed( 4 );
return [
'}'
].join( '\n' );
const chunks = [
parameters.extensionClipCullDistance ? '#extension
GL_ANGLE_clip_cull_distance : require' : '',
parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw :
require' : '',
];
let locationSize = 1;
if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;
attributes[ name ] = {
type: info.type,
location: gl.getAttribLocation( program, name ),
locationSize: locationSize
};
return attributes;
return string
.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
.replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
.replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )
.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
.replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g,
parameters.numSpotLightShadowsWithMaps )
.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
.replace( /NUM_POINT_LIGHT_SHADOWS/g,
parameters.numPointLightShadows );
}
return string
.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes -
parameters.numClipIntersection ) );
// Resolve Includes
} else {
throw new Error( 'Can not resolve #include <' + include + '>' );
// Unroll Loops
string += snippet
.replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
.replace( /UNROLLED_LOOP_INDEX/g, i );
return string;
//
return precisionstring;
}
function generateShadowMapTypeDefine( parameters ) {
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';
shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';
shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';
return shadowMapTypeDefine;
if ( parameters.envMap ) {
switch ( parameters.envMapMode ) {
case CubeReflectionMapping:
case CubeRefractionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
break;
case CubeUVReflectionMapping:
envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
break;
return envMapTypeDefine;
if ( parameters.envMap ) {
switch ( parameters.envMapMode ) {
case CubeRefractionMapping:
envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
break;
}
return envMapModeDefine;
if ( parameters.envMap ) {
switch ( parameters.combine ) {
case MultiplyOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
break;
case MixOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
break;
case AddOperation:
envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
break;
return envMapBlendingDefine;
const gl = renderer.getContext();
const defines = parameters.defines;
if ( parameters.isRawShaderMaterial ) {
prefixVertex = [
customDefines
if ( prefixVertex.length > 0 ) {
prefixVertex += '\n';
prefixFragment = [
customDefines
if ( prefixFragment.length > 0 ) {
prefixFragment += '\n';
} else {
prefixVertex = [
generatePrecision( parameters ),
'#define SHADER_TYPE ' + parameters.shaderType,
'#define SHADER_NAME ' + parameters.shaderName,
customDefines,
parameters.extensionClipCullDistance ? '#define
USE_CLIP_DISTANCE' : '',
parameters.batching ? '#define USE_BATCHING' : '',
parameters.batchingColor ? '#define USE_BATCHING_COLOR' : '',
parameters.instancing ? '#define USE_INSTANCING' : '',
parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
parameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '',
//
'#ifdef USE_INSTANCING',
'#endif',
'#ifdef USE_INSTANCING_COLOR',
'#ifdef USE_INSTANCING_MORPH',
'#endif',
'#ifdef USE_UV1',
'#endif',
'#ifdef USE_UV2',
'#endif',
'#ifdef USE_UV3',
'#endif',
'#ifdef USE_TANGENT',
'#endif',
'#endif',
'#ifdef USE_SKINNING',
'#endif',
'\n'
prefixFragment = [
generatePrecision( parameters ),
customDefines,
'\n'
prefixVertex = [
customVertexExtensions,
'#define attribute in',
'#define varying out',
'#define texture2D texture'
].join( '\n' ) + '\n' + prefixVertex;
prefixFragment = [
'#define varying in',
( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0)
out highp vec4 pc_fragColor;',
( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor
pc_fragColor',
'#define gl_FragDepthEXT gl_FragDepth',
'#define texture2D texture',
'#define textureCube texture',
'#define texture2DProj textureProj',
'#define texture2DLodEXT textureLod',
'#define texture2DProjLodEXT textureProjLod',
'#define textureCubeLodEXT textureLod',
'#define texture2DGradEXT textureGrad',
'#define texture2DProjGradEXT textureProjGrad',
'#define textureCubeGradEXT textureGrad'
].join( '\n' ) + '\n' + prefixFragment;
gl.linkProgram( program );
runnable = false;
} else {
// default error reporting
console.error(
'THREE.WebGLProgram: Shader Error ' +
gl.getError() + ' - ' +
'VALIDATE_STATUS ' +
gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
'Material Name: ' + self.name + '\n' +
'Material Type: ' + self.type + '\n\n' +
'Program Info Log: ' + programLog + '\n' +
vertexErrors + '\n' +
fragmentErrors
);
haveDiagnostics = false;
if ( haveDiagnostics ) {
self.diagnostics = {
runnable: runnable,
programLog: programLog,
vertexShader: {
log: vertexLog,
prefix: prefixVertex
},
fragmentShader: {
log: fragmentLog,
prefix: prefixFragment
};
}
}
// Clean up
gl.deleteShader( glVertexShader );
gl.deleteShader( glFragmentShader );
let cachedUniforms;
this.getUniforms = function () {
return cachedUniforms;
};
let cachedAttributes;
this.getAttributes = function () {
return cachedAttributes;
};
this.isReady = function () {
if ( programReady === false ) {
return programReady;
};
// free resource
this.destroy = function () {
bindingStates.releaseStatesOfProgram( this );
gl.deleteProgram( program );
this.program = undefined;
};
//
this.type = parameters.shaderType;
this.name = parameters.shaderName;
this.id = programIdCount ++;
this.cacheKey = cacheKey;
this.usedTimes = 1;
this.program = program;
this.vertexShader = glVertexShader;
this.fragmentShader = glFragmentShader;
return this;
let _id = 0;
class WebGLShaderCache {
constructor() {
update( material ) {
materialShaders.add( vertexShaderStage );
vertexShaderStage.usedTimes ++;
materialShaders.add( fragmentShaderStage );
fragmentShaderStage.usedTimes ++;
return this;
remove( material ) {
shaderStage.usedTimes --;
if ( shaderStage.usedTimes === 0 )
this.shaderCache.delete( shaderStage.code );
this.materialCache.delete( material );
return this;
getVertexShaderID( material ) {
getFragmentShaderID( material ) {
dispose() {
this.shaderCache.clear();
this.materialCache.clear();
_getShaderCacheForMaterial( material ) {
return set;
_getShaderStage( code ) {
return stage;
class WebGLShaderStage {
constructor( code ) {
this.code = code;
this.usedTimes = 0;
const shaderIDs = {
MeshDepthMaterial: 'depth',
MeshDistanceMaterial: 'distanceRGBA',
MeshNormalMaterial: 'normal',
MeshBasicMaterial: 'basic',
MeshLambertMaterial: 'lambert',
MeshPhongMaterial: 'phong',
MeshToonMaterial: 'toon',
MeshStandardMaterial: 'physical',
MeshPhysicalMaterial: 'physical',
MeshMatcapMaterial: 'matcap',
LineBasicMaterial: 'basic',
LineDashedMaterial: 'dashed',
PointsMaterial: 'points',
ShadowMaterial: 'shadow',
SpriteMaterial: 'sprite'
};
_activeChannels.add( value );
console.warn( 'THREE.WebGLProgram.getParameters:',
material.precision, 'not supported, using', precision, 'instead.' );
//
const morphAttribute = geometry.morphAttributes.position ||
geometry.morphAttributes.normal || geometry.morphAttributes.color;
const morphTargetsCount = ( morphAttribute !== undefined ) ?
morphAttribute.length : 0;
let morphTextureStride = 0;
//
if ( shaderID ) {
vertexShader = shader.vertexShader;
fragmentShader = shader.fragmentShader;
} else {
vertexShader = material.vertexShader;
fragmentShader = material.fragmentShader;
_customShaders.update( material );
if ( material.toneMapped ) {
toneMapping = renderer.toneMapping;
const parameters = {
shaderID: shaderID,
shaderType: material.type,
shaderName: material.name,
vertexShader: vertexShader,
fragmentShader: fragmentShader,
defines: material.defines,
customVertexShaderID: customVertexShaderID,
customFragmentShaderID: customFragmentShaderID,
precision: precision,
batching: IS_BATCHEDMESH,
batchingColor: IS_BATCHEDMESH && object._colorsTexture !== null,
instancing: IS_INSTANCEDMESH,
instancingColor: IS_INSTANCEDMESH && object.instanceColor !==
null,
instancingMorph: IS_INSTANCEDMESH && object.morphTexture !==
null,
supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,
outputColorSpace: ( currentRenderTarget === null ) ?
renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ?
currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
alphaToCoverage: !! material.alphaToCoverage,
map: HAS_MAP,
matcap: HAS_MATCAP,
envMap: HAS_ENVMAP,
envMapMode: HAS_ENVMAP && envMap.mapping,
envMapCubeUVHeight: envMapCubeUVHeight,
aoMap: HAS_AOMAP,
lightMap: HAS_LIGHTMAP,
bumpMap: HAS_BUMPMAP,
normalMap: HAS_NORMALMAP,
displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,
emissiveMap: HAS_EMISSIVEMAP,
metalnessMap: HAS_METALNESSMAP,
roughnessMap: HAS_ROUGHNESSMAP,
anisotropy: HAS_ANISOTROPY,
anisotropyMap: HAS_ANISOTROPYMAP,
clearcoat: HAS_CLEARCOAT,
clearcoatMap: HAS_CLEARCOATMAP,
clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP,
clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP,
dispersion: HAS_DISPERSION,
iridescence: HAS_IRIDESCENCE,
iridescenceMap: HAS_IRIDESCENCEMAP,
iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,
sheen: HAS_SHEEN,
sheenColorMap: HAS_SHEEN_COLORMAP,
sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,
specularMap: HAS_SPECULARMAP,
specularColorMap: HAS_SPECULAR_COLORMAP,
specularIntensityMap: HAS_SPECULAR_INTENSITYMAP,
transmission: HAS_TRANSMISSION,
transmissionMap: HAS_TRANSMISSIONMAP,
thicknessMap: HAS_THICKNESSMAP,
gradientMap: HAS_GRADIENTMAP,
alphaMap: HAS_ALPHAMAP,
alphaTest: HAS_ALPHATEST,
alphaHash: HAS_ALPHAHASH,
combine: material.combine,
//
//
fog: !! fog,
useFog: material.fog === true,
fogExp2: ( !! fog && fog.isFogExp2 ),
numDirLights: lights.directional.length,
numPointLights: lights.point.length,
numSpotLights: lights.spot.length,
numSpotLightMaps: lights.spotLightMap.length,
numRectAreaLights: lights.rectArea.length,
numHemiLights: lights.hemi.length,
numDirLightShadows: lights.directionalShadowMap.length,
numPointLightShadows: lights.pointShadowMap.length,
numSpotLightShadows: lights.spotShadowMap.length,
numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,
numLightProbes: lights.numLightProbes,
numClippingPlanes: clipping.numPlanes,
numClipIntersection: clipping.numIntersection,
dithering: material.dithering,
toneMapping: toneMapping,
premultipliedAlpha: material.premultipliedAlpha,
index0AttributeName: material.index0AttributeName,
rendererExtensionParallelShaderCompile:
extensions.has( 'KHR_parallel_shader_compile' ),
customProgramCacheKey: material.customProgramCacheKey()
};
parameters.vertexUv1s = _activeChannels.has( 1 );
parameters.vertexUv2s = _activeChannels.has( 2 );
parameters.vertexUv3s = _activeChannels.has( 3 );
_activeChannels.clear();
return parameters;
}
if ( parameters.shaderID ) {
array.push( parameters.shaderID );
} else {
array.push( parameters.customVertexShaderID );
array.push( parameters.customFragmentShaderID );
array.push( name );
array.push( parameters.defines[ name ] );
array.push( parameters.customProgramCacheKey );
return array.join();
array.push( parameters.precision );
array.push( parameters.outputColorSpace );
array.push( parameters.envMapMode );
array.push( parameters.envMapCubeUVHeight );
array.push( parameters.mapUv );
array.push( parameters.alphaMapUv );
array.push( parameters.lightMapUv );
array.push( parameters.aoMapUv );
array.push( parameters.bumpMapUv );
array.push( parameters.normalMapUv );
array.push( parameters.displacementMapUv );
array.push( parameters.emissiveMapUv );
array.push( parameters.metalnessMapUv );
array.push( parameters.roughnessMapUv );
array.push( parameters.anisotropyMapUv );
array.push( parameters.clearcoatMapUv );
array.push( parameters.clearcoatNormalMapUv );
array.push( parameters.clearcoatRoughnessMapUv );
array.push( parameters.iridescenceMapUv );
array.push( parameters.iridescenceThicknessMapUv );
array.push( parameters.sheenColorMapUv );
array.push( parameters.sheenRoughnessMapUv );
array.push( parameters.specularMapUv );
array.push( parameters.specularColorMapUv );
array.push( parameters.specularIntensityMapUv );
array.push( parameters.transmissionMapUv );
array.push( parameters.thicknessMapUv );
array.push( parameters.combine );
array.push( parameters.fogExp2 );
array.push( parameters.sizeAttenuation );
array.push( parameters.morphTargetsCount );
array.push( parameters.morphAttributeCount );
array.push( parameters.numDirLights );
array.push( parameters.numPointLights );
array.push( parameters.numSpotLights );
array.push( parameters.numSpotLightMaps );
array.push( parameters.numHemiLights );
array.push( parameters.numRectAreaLights );
array.push( parameters.numDirLightShadows );
array.push( parameters.numPointLightShadows );
array.push( parameters.numSpotLightShadows );
array.push( parameters.numSpotLightShadowsWithMaps );
array.push( parameters.numLightProbes );
array.push( parameters.shadowMapType );
array.push( parameters.toneMapping );
array.push( parameters.numClippingPlanes );
array.push( parameters.numClipIntersection );
array.push( parameters.depthPacking );
_programLayers.disableAll();
if ( parameters.supportsVertexTextures )
_programLayers.enable( 0 );
if ( parameters.instancing )
_programLayers.enable( 1 );
if ( parameters.instancingColor )
_programLayers.enable( 2 );
if ( parameters.instancingMorph )
_programLayers.enable( 3 );
if ( parameters.matcap )
_programLayers.enable( 4 );
if ( parameters.envMap )
_programLayers.enable( 5 );
if ( parameters.normalMapObjectSpace )
_programLayers.enable( 6 );
if ( parameters.normalMapTangentSpace )
_programLayers.enable( 7 );
if ( parameters.clearcoat )
_programLayers.enable( 8 );
if ( parameters.iridescence )
_programLayers.enable( 9 );
if ( parameters.alphaTest )
_programLayers.enable( 10 );
if ( parameters.vertexColors )
_programLayers.enable( 11 );
if ( parameters.vertexAlphas )
_programLayers.enable( 12 );
if ( parameters.vertexUv1s )
_programLayers.enable( 13 );
if ( parameters.vertexUv2s )
_programLayers.enable( 14 );
if ( parameters.vertexUv3s )
_programLayers.enable( 15 );
if ( parameters.vertexTangents )
_programLayers.enable( 16 );
if ( parameters.anisotropy )
_programLayers.enable( 17 );
if ( parameters.alphaHash )
_programLayers.enable( 18 );
if ( parameters.batching )
_programLayers.enable( 19 );
if ( parameters.dispersion )
_programLayers.enable( 20 );
if ( parameters.batchingColor )
_programLayers.enable( 21 );
array.push( _programLayers.mask );
_programLayers.disableAll();
if ( parameters.fog )
_programLayers.enable( 0 );
if ( parameters.useFog )
_programLayers.enable( 1 );
if ( parameters.flatShading )
_programLayers.enable( 2 );
if ( parameters.logarithmicDepthBuffer )
_programLayers.enable( 3 );
if ( parameters.reverseDepthBuffer )
_programLayers.enable( 4 );
if ( parameters.skinning )
_programLayers.enable( 5 );
if ( parameters.morphTargets )
_programLayers.enable( 6 );
if ( parameters.morphNormals )
_programLayers.enable( 7 );
if ( parameters.morphColors )
_programLayers.enable( 8 );
if ( parameters.premultipliedAlpha )
_programLayers.enable( 9 );
if ( parameters.shadowMapEnabled )
_programLayers.enable( 10 );
if ( parameters.doubleSided )
_programLayers.enable( 11 );
if ( parameters.flipSided )
_programLayers.enable( 12 );
if ( parameters.useDepthPacking )
_programLayers.enable( 13 );
if ( parameters.dithering )
_programLayers.enable( 14 );
if ( parameters.transmission )
_programLayers.enable( 15 );
if ( parameters.sheen )
_programLayers.enable( 16 );
if ( parameters.opaque )
_programLayers.enable( 17 );
if ( parameters.pointsUvs )
_programLayers.enable( 18 );
if ( parameters.decodeVideoTexture )
_programLayers.enable( 19 );
if ( parameters.decodeVideoTextureEmissive )
_programLayers.enable( 20 );
if ( parameters.alphaToCoverage )
_programLayers.enable( 21 );
array.push( _programLayers.mask );
if ( shaderID ) {
} else {
uniforms = material.uniforms;
return uniforms;
let program;
program = preexistingProgram;
++ program.usedTimes;
break;
}
if ( program === undefined ) {
return program;
if ( -- program.usedTimes === 0 ) {
_customShaders.remove( material );
function dispose() {
_customShaders.dispose();
return {
getParameters: getParameters,
getProgramCacheKey: getProgramCacheKey,
getUniforms: getUniforms,
acquireProgram: acquireProgram,
releaseProgram: releaseProgram,
releaseShaderCache: releaseShaderCache,
// Exposed for resource monitoring & error feedback via renderer.info:
programs: programs,
dispose: dispose
};
function WebGLProperties() {
map = {};
properties.set( object, map );
return map;
properties.delete( object );
function dispose() {
return {
has: has,
get: get,
remove: remove,
update: update,
dispose: dispose
};
function painterSortStable( a, b ) {
} else {
function reversePainterSortStable( a, b ) {
} else {
function WebGLRenderList() {
function init() {
renderItemsIndex = 0;
opaque.length = 0;
transmissive.length = 0;
transparent.length = 0;
renderItem = {
id: object.id,
object: object,
geometry: geometry,
material: material,
groupOrder: groupOrder,
renderOrder: object.renderOrder,
z: z,
group: group
};
} else {
renderItem.id = object.id;
renderItem.object = object;
renderItem.geometry = geometry;
renderItem.material = material;
renderItem.groupOrder = groupOrder;
renderItem.renderOrder = object.renderOrder;
renderItem.z = z;
renderItem.group = group;
renderItemsIndex ++;
return renderItem;
transmissive.push( renderItem );
transparent.push( renderItem );
} else {
opaque.push( renderItem );
transmissive.unshift( renderItem );
transparent.unshift( renderItem );
} else {
opaque.unshift( renderItem );
function finish() {
renderItem.id = null;
renderItem.object = null;
renderItem.geometry = null;
renderItem.material = null;
renderItem.group = null;
return {
opaque: opaque,
transmissive: transmissive,
transparent: transparent,
init: init,
push: push,
unshift: unshift,
finish: finish,
sort: sort
};
function WebGLRenderLists() {
} else {
} else {
return list;
function dispose() {
return {
get: get,
dispose: dispose
};
function UniformsCache() {
let uniforms;
switch ( light.type ) {
case 'DirectionalLight':
uniforms = {
direction: new Vector3(),
color: new Color()
};
break;
case 'SpotLight':
uniforms = {
position: new Vector3(),
direction: new Vector3(),
color: new Color(),
distance: 0,
coneCos: 0,
penumbraCos: 0,
decay: 0
};
break;
case 'PointLight':
uniforms = {
position: new Vector3(),
color: new Color(),
distance: 0,
decay: 0
};
break;
case 'HemisphereLight':
uniforms = {
direction: new Vector3(),
skyColor: new Color(),
groundColor: new Color()
};
break;
case 'RectAreaLight':
uniforms = {
color: new Color(),
position: new Vector3(),
halfWidth: new Vector3(),
halfHeight: new Vector3()
};
break;
}
return uniforms;
};
function ShadowUniformsCache() {
return {
let uniforms;
switch ( light.type ) {
case 'DirectionalLight':
uniforms = {
shadowIntensity: 1,
shadowBias: 0,
shadowNormalBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2()
};
break;
case 'SpotLight':
uniforms = {
shadowIntensity: 1,
shadowBias: 0,
shadowNormalBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2()
};
break;
case 'PointLight':
uniforms = {
shadowIntensity: 1,
shadowBias: 0,
shadowNormalBias: 0,
shadowRadius: 1,
shadowMapSize: new Vector2(),
shadowCameraNear: 1,
shadowCameraFar: 1000
};
break;
return uniforms;
};
let nextVersion = 0;
const state = {
version: 0,
hash: {
directionalLength: - 1,
pointLength: - 1,
spotLength: - 1,
rectAreaLength: - 1,
hemiLength: - 1,
numDirectionalShadows: - 1,
numPointShadows: - 1,
numSpotShadows: - 1,
numSpotMaps: - 1,
numLightProbes: - 1
},
ambient: [ 0, 0, 0 ],
probe: [],
directional: [],
directionalShadow: [],
directionalShadowMap: [],
directionalShadowMatrix: [],
spot: [],
spotLightMap: [],
spotShadow: [],
spotShadowMap: [],
spotLightMatrix: [],
rectArea: [],
rectAreaLTC1: null,
rectAreaLTC2: null,
point: [],
pointShadow: [],
pointShadowMap: [],
pointShadowMatrix: [],
hemi: [],
numSpotLightShadowsWithMaps: 0,
numLightProbes: 0
};
let r = 0, g = 0, b = 0;
let directionalLength = 0;
let pointLength = 0;
let spotLength = 0;
let rectAreaLength = 0;
let hemiLength = 0;
let numDirectionalShadows = 0;
let numPointShadows = 0;
let numSpotShadows = 0;
let numSpotMaps = 0;
let numSpotShadowsWithMaps = 0;
let numLightProbes = 0;
r += color.r * intensity;
g += color.g * intensity;
b += color.b * intensity;
} else if ( light.isLightProbe ) {
numLightProbes ++;
} else if ( light.isDirectionalLight ) {
if ( light.castShadow ) {
shadowUniforms.shadowIntensity = shadow.intensity;
shadowUniforms.shadowBias = shadow.bias;
shadowUniforms.shadowNormalBias = shadow.normalBias;
shadowUniforms.shadowRadius = shadow.radius;
shadowUniforms.shadowMapSize = shadow.mapSize;
state.directionalShadow[ directionalLength ] =
shadowUniforms;
state.directionalShadowMap[ directionalLength ] =
shadowMap;
state.directionalShadowMatrix[ directionalLength ] =
light.shadow.matrix;
numDirectionalShadows ++;
directionalLength ++;
} else if ( light.isSpotLight ) {
uniforms.position.setFromMatrixPosition( light.matrixWorld );
if ( light.map ) {
if ( light.castShadow ) {
shadowUniforms.shadowIntensity = shadow.intensity;
shadowUniforms.shadowBias = shadow.bias;
shadowUniforms.shadowNormalBias = shadow.normalBias;
shadowUniforms.shadowRadius = shadow.radius;
shadowUniforms.shadowMapSize = shadow.mapSize;
numSpotShadows ++;
spotLength ++;
} else if ( light.isRectAreaLight ) {
rectAreaLength ++;
} else if ( light.isPointLight ) {
const uniforms = cache.get( light );
if ( light.castShadow ) {
shadowUniforms.shadowIntensity = shadow.intensity;
shadowUniforms.shadowBias = shadow.bias;
shadowUniforms.shadowNormalBias = shadow.normalBias;
shadowUniforms.shadowRadius = shadow.radius;
shadowUniforms.shadowMapSize = shadow.mapSize;
shadowUniforms.shadowCameraNear = shadow.camera.near;
shadowUniforms.shadowCameraFar = shadow.camera.far;
numPointShadows ++;
pointLength ++;
} else if ( light.isHemisphereLight ) {
hemiLength ++;
if ( rectAreaLength > 0 ) {
state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;
state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;
} else {
state.rectAreaLTC1 = UniformsLib.LTC_HALF_1;
state.rectAreaLTC2 = UniformsLib.LTC_HALF_2;
state.ambient[ 0 ] = r;
state.ambient[ 1 ] = g;
state.ambient[ 2 ] = b;
state.directional.length = directionalLength;
state.spot.length = spotLength;
state.rectArea.length = rectAreaLength;
state.point.length = pointLength;
state.hemi.length = hemiLength;
state.directionalShadow.length = numDirectionalShadows;
state.directionalShadowMap.length = numDirectionalShadows;
state.pointShadow.length = numPointShadows;
state.pointShadowMap.length = numPointShadows;
state.spotShadow.length = numSpotShadows;
state.spotShadowMap.length = numSpotShadows;
state.directionalShadowMatrix.length = numDirectionalShadows;
state.pointShadowMatrix.length = numPointShadows;
state.spotLightMatrix.length = numSpotShadows + numSpotMaps -
numSpotShadowsWithMaps;
state.spotLightMap.length = numSpotMaps;
state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
state.numLightProbes = numLightProbes;
hash.directionalLength = directionalLength;
hash.pointLength = pointLength;
hash.spotLength = spotLength;
hash.rectAreaLength = rectAreaLength;
hash.hemiLength = hemiLength;
hash.numDirectionalShadows = numDirectionalShadows;
hash.numPointShadows = numPointShadows;
hash.numSpotShadows = numSpotShadows;
hash.numSpotMaps = numSpotMaps;
hash.numLightProbes = numLightProbes;
state.version = nextVersion ++;
let directionalLength = 0;
let pointLength = 0;
let spotLength = 0;
let rectAreaLength = 0;
let hemiLength = 0;
if ( light.isDirectionalLight ) {
uniforms.direction.setFromMatrixPosition( light.matrixWorld
);
vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( vector3 );
uniforms.direction.transformDirection( viewMatrix );
directionalLength ++;
} else if ( light.isSpotLight ) {
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
uniforms.direction.setFromMatrixPosition( light.matrixWorld
);
vector3.setFromMatrixPosition( light.target.matrixWorld );
uniforms.direction.sub( vector3 );
uniforms.direction.transformDirection( viewMatrix );
spotLength ++;
} else if ( light.isRectAreaLight ) {
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
uniforms.halfWidth.applyMatrix4( matrix42 );
uniforms.halfHeight.applyMatrix4( matrix42 );
rectAreaLength ++;
} else if ( light.isPointLight ) {
uniforms.position.setFromMatrixPosition( light.matrixWorld );
uniforms.position.applyMatrix4( viewMatrix );
pointLength ++;
} else if ( light.isHemisphereLight ) {
uniforms.direction.setFromMatrixPosition( light.matrixWorld
);
uniforms.direction.transformDirection( viewMatrix );
hemiLength ++;
return {
setup: setup,
setupView: setupView,
state: state
};
state.camera = camera;
lightsArray.length = 0;
shadowsArray.length = 0;
}
lightsArray.push( light );
shadowsArray.push( shadowLight );
function setupLights() {
lights.setup( lightsArray );
const state = {
lightsArray: lightsArray,
shadowsArray: shadowsArray,
camera: null,
lights: lights,
transmissionRenderTarget: {}
};
return {
init: init,
state: state,
setupLights: setupLights,
setupLightsView: setupLightsView,
pushLight: pushLight,
pushShadow: pushShadow
};
} else {
} else {
return renderState;
function dispose() {
return {
get: get,
dispose: dispose
};
_materialCache = {},
_maxTextureSize = capabilities.maxTextureSize;
vertexShader: vertex,
fragmentShader: fragment
} );
this.enabled = false;
this.autoUpdate = true;
this.needsUpdate = false;
this.type = PCFShadowMap;
let _previousType = this.type;
_shadowMapSize.copy( shadow.mapSize );
_shadowMapSize.multiply( shadowFrameExtents );
_viewportSize.copy( shadow.mapSize );
shadow.map.dispose();
shadow.camera.updateProjectionMatrix();
renderer.setRenderTarget( shadow.map );
renderer.clear();
_viewport.set(
_viewportSize.x * viewport.x,
_viewportSize.y * viewport.y,
_viewportSize.x * viewport.z,
_viewportSize.y * viewport.w
);
_state.viewport( _viewport );
shadow.updateMatrices( light, vp );
_frustum = shadow.getFrustum();
shadow.needsUpdate = false;
_previousType = this.type;
scope.needsUpdate = false;
};
if ( shadowMaterialVertical.defines.VSM_SAMPLES !==
shadow.blurSamples ) {
shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
shadowMaterialHorizontal.defines.VSM_SAMPLES =
shadow.blurSamples;
shadowMaterialVertical.needsUpdate = true;
shadowMaterialHorizontal.needsUpdate = true;
// vertical pass
shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
shadowMaterialVertical.uniforms.radius.value = shadow.radius;
renderer.setRenderTarget( shadow.mapPass );
renderer.clear();
renderer.renderBufferDirect( camera, null, geometry,
shadowMaterialVertical, fullScreenMesh, null );
// horizontal pass
shadowMaterialHorizontal.uniforms.shadow_pass.value =
shadow.mapPass.texture;
shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
renderer.setRenderTarget( shadow.map );
renderer.clear();
renderer.renderBufferDirect( camera, null, geometry,
shadowMaterialHorizontal, fullScreenMesh, null );
result = customMaterial;
} else {
materialsForVariant = {};
_materialCache[ keyA ] = materialsForVariant;
cachedMaterial = result.clone();
materialsForVariant[ keyB ] = cachedMaterial;
material.addEventListener( 'dispose',
onMaterialDispose );
}
result = cachedMaterial;
result.visible = material.visible;
result.wireframe = material.wireframe;
} else {
result.alphaMap = material.alphaMap;
result.alphaTest = material.alphaTest;
result.map = material.map;
result.clipShadows = material.clipShadows;
result.clippingPlanes = material.clippingPlanes;
result.clipIntersection = material.clipIntersection;
result.displacementMap = material.displacementMap;
result.displacementScale = material.displacementScale;
result.displacementBias = material.displacementBias;
result.wireframeLinewidth = material.wireframeLinewidth;
result.linewidth = material.linewidth;
return result;
object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse,
object.matrixWorld );
if ( Array.isArray( material ) ) {
const depthMaterial =
getDepthMaterial( object, groupMaterial, light, type );
} else if ( material.visible ) {
}
}
if ( uuid in cache ) {
const reversedFuncs = {
[ NeverDepth ]: AlwaysDepth,
[ LessDepth ]: GreaterDepth,
[ EqualDepth ]: NotEqualDepth,
[ LessEqualDepth ]: GreaterEqualDepth,
[ AlwaysDepth ]: NeverDepth,
[ GreaterDepth ]: LessDepth,
[ NotEqualDepth ]: EqualDepth,
[ GreaterEqualDepth ]: LessEqualDepth,
};
function ColorBuffer() {
return {
},
locked = lock;
},
r *= a; g *= a; b *= a;
color.set( r, g, b, a );
gl.clearColor( r, g, b, a );
currentColorClear.copy( color );
},
reset: function () {
locked = false;
currentColorMask = null;
currentColorClear.set( - 1, 0, 0, 0 ); // set to invalid
state
};
function DepthBuffer() {
let locked = false;
let reversed = false;
return {
if ( reversed ) {
ext.clipControlEXT( ext.LOWER_LEFT_EXT,
ext.ZERO_TO_ONE_EXT );
} else {
ext.clipControlEXT( ext.LOWER_LEFT_EXT,
ext.NEGATIVE_ONE_TO_ONE_EXT );
reversed = value;
},
getReversed: function () {
return reversed;
},
if ( depthTest ) {
enable( gl.DEPTH_TEST );
} else {
disable( gl.DEPTH_TEST );
},
gl.depthMask( depthMask );
currentDepthMask = depthMask;
},
switch ( depthFunc ) {
case NeverDepth:
gl.depthFunc( gl.NEVER );
break;
case AlwaysDepth:
gl.depthFunc( gl.ALWAYS );
break;
case LessDepth:
gl.depthFunc( gl.LESS );
break;
case LessEqualDepth:
gl.depthFunc( gl.LEQUAL );
break;
case EqualDepth:
gl.depthFunc( gl.EQUAL );
break;
case GreaterEqualDepth:
gl.depthFunc( gl.GEQUAL );
break;
case GreaterDepth:
gl.depthFunc( gl.GREATER );
break;
case NotEqualDepth:
gl.depthFunc( gl.NOTEQUAL );
break;
default:
gl.depthFunc( gl.LEQUAL );
currentDepthFunc = depthFunc;
},
locked = lock;
},
if ( reversed ) {
depth = 1 - depth;
gl.clearDepth( depth );
currentDepthClear = depth;
},
reset: function () {
locked = false;
currentDepthMask = null;
currentDepthFunc = null;
currentDepthClear = null;
reversed = false;
};
function StencilBuffer() {
return {
if ( ! locked ) {
if ( stencilTest ) {
enable( gl.STENCIL_TEST );
} else {
disable( gl.STENCIL_TEST );
},
gl.stencilMask( stencilMask );
currentStencilMask = stencilMask;
},
currentStencilFunc = stencilFunc;
currentStencilRef = stencilRef;
currentStencilFuncMask = stencilMask;
},
},
locked = lock;
},
gl.clearStencil( stencil );
currentStencilClear = stencil;
},
reset: function () {
locked = false;
currentStencilMask = null;
currentStencilFunc = null;
currentStencilRef = null;
currentStencilFuncMask = null;
currentStencilFail = null;
currentStencilZFail = null;
currentStencilZPass = null;
currentStencilClear = null;
};
//
} else {
return texture;
// init
colorBuffer.setClear( 0, 0, 0, 1 );
depthBuffer.setClear( 1 );
stencilBuffer.setClear( 0 );
enable( gl.DEPTH_TEST );
depthBuffer.setFunc( LessEqualDepth );
setFlipSided( false );
setCullFace( CullFaceBack );
enable( gl.CULL_FACE );
setBlending( NoBlending );
//
function enable( id ) {
gl.enable( id );
enabledCapabilities[ id ] = true;
function disable( id ) {
if ( enabledCapabilities[ id ] !== false ) {
gl.disable( id );
enabledCapabilities[ id ] = false;
currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] =
framebuffer;
return true;
return false;
if ( renderTarget ) {
drawBuffers = [];
currentDrawbuffers.set( framebuffer, drawBuffers );
drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;
drawBuffers.length = textures.length;
needsUpdate = true;
} else {
drawBuffers[ 0 ] = gl.BACK;
needsUpdate = true;
if ( needsUpdate ) {
gl.drawBuffers( drawBuffers );
gl.useProgram( program );
currentProgram = program;
return true;
return false;
const equationToGL = {
[ AddEquation ]: gl.FUNC_ADD,
[ SubtractEquation ]: gl.FUNC_SUBTRACT,
[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
};
const factorToGL = {
[ ZeroFactor ]: gl.ZERO,
[ OneFactor ]: gl.ONE,
[ SrcColorFactor ]: gl.SRC_COLOR,
[ SrcAlphaFactor ]: gl.SRC_ALPHA,
[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
[ DstColorFactor ]: gl.DST_COLOR,
[ DstAlphaFactor ]: gl.DST_ALPHA,
[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
[ ConstantColorFactor ]: gl.CONSTANT_COLOR,
[ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
[ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
[ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
};
disable( gl.BLEND );
currentBlendingEnabled = false;
return;
enable( gl.BLEND );
currentBlendingEnabled = true;
gl.blendEquation( gl.FUNC_ADD );
currentBlendEquation = AddEquation;
currentBlendEquationAlpha = AddEquation;
}
if ( premultipliedAlpha ) {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.ONE,
gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.ONE, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFuncSeparate( gl.ZERO,
gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
break;
case MultiplyBlending:
gl.blendFuncSeparate( gl.ZERO,
gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );
break;
default:
console.error( 'THREE.WebGLState: Invalid
blending: ', blending );
break;
} else {
switch ( blending ) {
case NormalBlending:
gl.blendFuncSeparate( gl.SRC_ALPHA,
gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
break;
case AdditiveBlending:
gl.blendFunc( gl.SRC_ALPHA, gl.ONE );
break;
case SubtractiveBlending:
gl.blendFuncSeparate( gl.ZERO,
gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
break;
case MultiplyBlending:
gl.blendFunc( gl.ZERO, gl.SRC_COLOR );
break;
default:
console.error( 'THREE.WebGLState: Invalid
blending: ', blending );
break;
}
}
currentBlendSrc = null;
currentBlendDst = null;
currentBlendSrcAlpha = null;
currentBlendDstAlpha = null;
currentBlendColor.set( 0, 0, 0 );
currentBlendAlpha = 0;
currentBlending = blending;
currentPremultipledAlpha = premultipliedAlpha;
return;
// custom blending
currentBlendEquation = blendEquation;
currentBlendEquationAlpha = blendEquationAlpha;
currentBlendSrc = blendSrc;
currentBlendDst = blendDst;
currentBlendSrcAlpha = blendSrcAlpha;
currentBlendDstAlpha = blendDstAlpha;
currentBlendColor.copy( blendColor );
currentBlendAlpha = blendAlpha;
}
currentBlending = blending;
currentPremultipledAlpha = false;
setFlipSided( flipSided );
depthBuffer.setFunc( material.depthFunc );
depthBuffer.setTest( material.depthTest );
depthBuffer.setMask( material.depthWrite );
colorBuffer.setMask( material.colorWrite );
stencilBuffer.setMask( material.stencilWriteMask );
stencilBuffer.setFunc( material.stencilFunc, material.stencilRef,
material.stencilFuncMask );
stencilBuffer.setOp( material.stencilFail, material.stencilZFail,
material.stencilZPass );
//
if ( flipSided ) {
gl.frontFace( gl.CW );
} else {
gl.frontFace( gl.CCW );
currentFlipSided = flipSided;
enable( gl.CULL_FACE );
gl.cullFace( gl.BACK );
gl.cullFace( gl.FRONT );
} else {
gl.cullFace( gl.FRONT_AND_BACK );
} else {
disable( gl.CULL_FACE );
currentCullFace = cullFace;
currentLineWidth = width;
}
function setPolygonOffset( polygonOffset, factor, units ) {
if ( polygonOffset ) {
enable( gl.POLYGON_OFFSET_FILL );
currentPolygonOffsetFactor = factor;
currentPolygonOffsetUnits = units;
} else {
disable( gl.POLYGON_OFFSET_FILL );
if ( scissorTest ) {
enable( gl.SCISSOR_TEST );
} else {
disable( gl.SCISSOR_TEST );
// texture
gl.activeTexture( webglSlot );
currentTextureSlot = webglSlot;
} else {
webglSlot = currentTextureSlot;
gl.activeTexture( webglSlot );
currentTextureSlot = webglSlot;
boundTexture.type = webglType;
boundTexture.texture = webglTexture;
function unbindTexture() {
boundTexture.type = undefined;
boundTexture.texture = undefined;
function compressedTexImage2D() {
try {
gl.compressedTexImage2D.apply( gl, arguments );
} catch ( error ) {
function compressedTexImage3D() {
try {
} catch ( error ) {
function texSubImage2D() {
try {
} catch ( error ) {
function texSubImage3D() {
try {
} catch ( error ) {
function compressedTexSubImage2D() {
try {
function compressedTexSubImage3D() {
try {
} catch ( error ) {
function texStorage2D() {
try {
} catch ( error ) {
function texStorage3D() {
try {
} catch ( error ) {
function texImage2D() {
try {
} catch ( error ) {
function texImage3D() {
try {
} catch ( error ) {
//
//
function reset() {
// reset state
gl.disable( gl.BLEND );
gl.disable( gl.CULL_FACE );
gl.disable( gl.DEPTH_TEST );
gl.disable( gl.POLYGON_OFFSET_FILL );
gl.disable( gl.SCISSOR_TEST );
gl.disable( gl.STENCIL_TEST );
gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );
gl.blendEquation( gl.FUNC_ADD );
gl.blendFunc( gl.ONE, gl.ZERO );
gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
gl.blendColor( 0, 0, 0, 0 );
gl.depthMask( true );
gl.depthFunc( gl.LESS );
depthBuffer.setReversed( false );
gl.clearDepth( 1 );
gl.stencilMask( 0xffffffff );
gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
gl.clearStencil( 0 );
gl.cullFace( gl.BACK );
gl.frontFace( gl.CCW );
gl.polygonOffset( 0, 0 );
gl.activeTexture( gl.TEXTURE0 );
gl.useProgram( null );
gl.lineWidth( 1 );
// reset internals
enabledCapabilities = {};
currentTextureSlot = null;
currentBoundTextures = {};
currentBoundFramebuffers = {};
currentDrawbuffers = new WeakMap();
defaultDrawbuffers = [];
currentProgram = null;
currentBlendingEnabled = false;
currentBlending = null;
currentBlendEquation = null;
currentBlendSrc = null;
currentBlendDst = null;
currentBlendEquationAlpha = null;
currentBlendSrcAlpha = null;
currentBlendDstAlpha = null;
currentBlendColor = new Color( 0, 0, 0 );
currentBlendAlpha = 0;
currentPremultipledAlpha = false;
currentFlipSided = null;
currentCullFace = null;
currentLineWidth = null;
currentPolygonOffsetFactor = null;
currentPolygonOffsetUnits = null;
colorBuffer.reset();
depthBuffer.reset();
stencilBuffer.reset();
}
return {
buffers: {
color: colorBuffer,
depth: depthBuffer,
stencil: stencilBuffer
},
enable: enable,
disable: disable,
bindFramebuffer: bindFramebuffer,
drawBuffers: drawBuffers,
useProgram: useProgram,
setBlending: setBlending,
setMaterial: setMaterial,
setFlipSided: setFlipSided,
setCullFace: setCullFace,
setLineWidth: setLineWidth,
setPolygonOffset: setPolygonOffset,
setScissorTest: setScissorTest,
activeTexture: activeTexture,
bindTexture: bindTexture,
unbindTexture: unbindTexture,
compressedTexImage2D: compressedTexImage2D,
compressedTexImage3D: compressedTexImage3D,
texImage2D: texImage2D,
texImage3D: texImage3D,
updateUBOMapping: updateUBOMapping,
uniformBlockBinding: uniformBlockBinding,
texStorage2D: texStorage2D,
texStorage3D: texStorage3D,
texSubImage2D: texSubImage2D,
texSubImage3D: texSubImage3D,
compressedTexSubImage2D: compressedTexSubImage2D,
compressedTexSubImage3D: compressedTexSubImage3D,
scissor: scissor,
viewport: viewport,
reset: reset
};
try {
} catch ( err ) {
return useOffscreenCanvas ?
// eslint-disable-next-line compat/compat
new OffscreenCanvas( width, height ) :
createElementNS( 'canvas' );
let scale = 1;
}
// only perform resize if necessary
if ( scale < 1 ) {
canvas.width = width;
canvas.height = height;
return canvas;
} else {
if ( 'data' in image ) {
return image;
return image;
_gl.generateMipmap( target );
extensions.get( 'EXT_color_buffer_float' );
return internalFormat;
let glInternalFormat;
if ( useStencil ) {
glInternalFormat = _gl.DEPTH24_STENCIL8;
glInternalFormat = _gl.DEPTH32F_STENCIL8;
glInternalFormat = _gl.DEPTH24_STENCIL8;
console.warn( 'DepthTexture: 16 bit depth attachment is not
supported with stencil. Using 24-bit attachment.' );
} else {
glInternalFormat = _gl.DEPTH_COMPONENT24;
glInternalFormat = _gl.DEPTH_COMPONENT32F;
glInternalFormat = _gl.DEPTH_COMPONENT16;
return glInternalFormat;
}
// user-defined mipmaps
return texture.mipmaps.length;
return image.mipmaps.length;
} else {
return 1;
//
deallocateTexture( texture );
if ( texture.isVideoTexture ) {
_videoTextures.delete( texture );
deallocateRenderTarget( renderTarget );
}
//
if ( webglTextures ) {
const webglTexture =
webglTextures[ textureProperties.__cacheKey ];
webglTexture.usedTimes --;
if ( webglTexture.usedTimes === 0 ) {
deleteTexture( texture );
_sources.delete( source );
properties.remove( texture );
info.memory.textures --;
renderTarget.depthTexture.dispose();
properties.remove( renderTarget.depthTexture );
if ( renderTarget.isWebGLCubeRenderTarget ) {
if
( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {
} else {
_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );
if ( renderTargetProperties.__webglDepthbuffer )
_gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );
} else {
if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) )
{
} else {
_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );
if ( renderTargetProperties.__webglDepthbuffer )
_gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );
if ( renderTargetProperties.__webglMultisampledFramebuffer )
_gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );
if ( renderTargetProperties.__webglColorRenderbuffer ) {
if ( renderTargetProperties.__webglColorRenderbuffer[
i ] )
_gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );
if ( renderTargetProperties.__webglDepthRenderbuffer )
_gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );
if ( attachmentProperties.__webglTexture ) {
_gl.deleteTexture( attachmentProperties.__webglTexture );
info.memory.textures --;
properties.remove( textures[ i ] );
properties.remove( renderTarget );
//
let textureUnits = 0;
function resetTextureUnits() {
textureUnits = 0;
function allocateTextureUnit() {
textureUnits += 1;
return textureUnit;
}
array.push( texture.wrapS );
array.push( texture.wrapT );
array.push( texture.wrapR || 0 );
array.push( texture.magFilter );
array.push( texture.minFilter );
array.push( texture.anisotropy );
array.push( texture.internalFormat );
array.push( texture.format );
array.push( texture.type );
array.push( texture.generateMipmaps );
array.push( texture.premultiplyAlpha );
array.push( texture.flipY );
array.push( texture.unpackAlignment );
array.push( texture.colorSpace );
return array.join();
//
} else {
state.bindTexture( _gl.TEXTURE_2D_ARRAY,
textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
state.bindTexture( _gl.TEXTURE_CUBE_MAP,
textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
const wrappingToGL = {
[ RepeatWrapping ]: _gl.REPEAT,
[ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
[ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
};
const filterToGL = {
[ NearestFilter ]: _gl.NEAREST,
[ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
[ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,
[ LinearFilter ]: _gl.LINEAR,
[ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
[ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
};
const compareToGL = {
[ NeverCompare ]: _gl.NEVER,
[ AlwaysCompare ]: _gl.ALWAYS,
[ LessCompare ]: _gl.LESS,
[ LessEqualCompare ]: _gl.LEQUAL,
[ EqualCompare ]: _gl.EQUAL,
[ GreaterEqualCompare ]: _gl.GEQUAL,
[ GreaterCompare ]: _gl.GREATER,
[ NotEqualCompare ]: _gl.NOTEQUAL
};
if ( texture.compareFunction ) {
_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE,
_gl.COMPARE_REF_TO_TEXTURE );
_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC,
compareToGL[ texture.compareFunction ] );
if ( texture.anisotropy > 1 ||
properties.get( texture ).__currentAnisotropy ) {
const extension =
extensions.get( 'EXT_texture_filter_anisotropic' );
_gl.texParameterf( textureType,
extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy,
capabilities.getMaxAnisotropy() ) );
properties.get( texture ).__currentAnisotropy =
texture.anisotropy;
textureProperties.__webglInit = true;
webglTextures = {};
_sources.set( source, webglTextures );
webglTextures[ textureCacheKey ] = {
texture: _gl.createTexture(),
usedTimes: 0
};
info.memory.textures ++;
forceUpload = true;
const webglTexture =
webglTextures[ textureProperties.__cacheKey ];
if ( webglTexture.usedTimes === 0 ) {
deleteTexture( texture );
textureProperties.__cacheKey = textureCacheKey;
textureProperties.__webglTexture = webglTextures[ textureCacheKey
].texture;
return forceUpload;
}
function uploadTexture( textureProperties, texture, slot ) {
if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture )
textureType = _gl.TEXTURE_2D_ARRAY;
if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;
const workingPrimaries =
ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
const texturePrimaries = texture.colorSpace === NoColorSpace ?
null : ColorManagement.getPrimaries( texture.colorSpace );
const unpackConversion = texture.colorSpace === NoColorSpace ||
workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
let mipmap;
const mipmaps = texture.mipmaps;
if ( texture.isDepthTexture ) {
glInternalFormat = getInternalDepthFormat( texture.format
=== DepthStencilFormat, texture.type );
//
if ( allocateMemory ) {
if ( useTexStorage ) {
state.texStorage2D( _gl.TEXTURE_2D, 1,
glInternalFormat, image.width, image.height );
} else {
state.texImage2D( _gl.TEXTURE_2D, 0,
glInternalFormat, image.width, image.height, 0, glFormat, glType, null );
} else if ( texture.isDataTexture ) {
if ( mipmaps.length > 0 ) {
mipmap = mipmaps[ i ];
if ( useTexStorage ) {
if ( dataReady ) {
} else {
state.texImage2D( _gl.TEXTURE_2D, i,
glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );
}
}
texture.generateMipmaps = false;
} else {
if ( useTexStorage ) {
if ( allocateMemory ) {
state.texStorage2D( _gl.TEXTURE_2D,
levels, glInternalFormat, image.width, image.height );
if ( dataReady ) {
state.texSubImage2D( _gl.TEXTURE_2D, 0,
0, 0, image.width, image.height, glFormat, glType, image.data );
} else {
state.texImage2D( _gl.TEXTURE_2D, 0,
glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );
} else if ( texture.isCompressedTexture ) {
if ( texture.isCompressedArrayTexture ) {
state.texStorage3D( _gl.TEXTURE_2D_ARRAY,
levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );
mipmap = mipmaps[ i ];
if ( useTexStorage ) {
if ( dataReady ) {
if
( texture.layerUpdates.size > 0 ) {
const
layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format,
texture.type );
for ( const
layerIndex of texture.layerUpdates ) {
const
layerData = mipmap.data.subarray(
texture.clearLayerUpdates();
} else {
state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0,
mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data );
} else {
} else {
console.warn( 'THREE.WebGLRenderer:
Attempt to load unsupported compressed texture format in .uploadTexture()' );
} else {
if ( useTexStorage ) {
if ( dataReady ) {
}
} else {
} else {
mipmap = mipmaps[ i ];
if ( useTexStorage ) {
if ( dataReady ) {
} else {
} else {
console.warn( 'THREE.WebGLRenderer:
Attempt to load unsupported compressed texture format in .uploadTexture()' );
} else {
if ( useTexStorage ) {
if ( dataReady ) {
} else {
state.texImage2D( _gl.TEXTURE_2D,
i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType,
mipmap.data );
} else if ( texture.isDataArrayTexture ) {
if ( useTexStorage ) {
if ( allocateMemory ) {
state.texStorage3D( _gl.TEXTURE_2D_ARRAY,
levels, glInternalFormat, image.width, image.height, image.depth );
if ( dataReady ) {
if ( texture.layerUpdates.size > 0 ) {
const layerByteLength =
getByteLength( image.width, image.height, texture.format, texture.type );
const layerData =
image.data.subarray(
layerIndex *
layerByteLength / image.data.BYTES_PER_ELEMENT,
( layerIndex + 1 ) *
layerByteLength / image.data.BYTES_PER_ELEMENT
);
texture.clearLayerUpdates();
} else {
state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width,
image.height, image.depth, glFormat, glType, image.data );
} else {
state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0,
glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType,
image.data );
} else if ( texture.isData3DTexture ) {
if ( useTexStorage ) {
if ( allocateMemory ) {
if ( dataReady ) {
state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0,
0, image.width, image.height, image.depth, glFormat, glType, image.data );
} else {
state.texImage3D( _gl.TEXTURE_3D, 0,
glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType,
image.data );
} else if ( texture.isFramebufferTexture ) {
if ( allocateMemory ) {
if ( useTexStorage ) {
} else {
state.texImage2D( _gl.TEXTURE_2D, i,
glInternalFormat, width, height, 0, glFormat, glType, null );
width >>= 1;
height >>= 1;
} else {
if ( mipmaps.length > 0 ) {
const dimensions =
getDimensions( mipmaps[ 0 ] );
mipmap = mipmaps[ i ];
if ( useTexStorage ) {
if ( dataReady ) {
} else {
state.texImage2D( _gl.TEXTURE_2D, i,
glInternalFormat, glFormat, glType, mipmap );
texture.generateMipmaps = false;
} else {
if ( useTexStorage ) {
if ( allocateMemory ) {
const dimensions =
getDimensions( image );
state.texStorage2D( _gl.TEXTURE_2D,
levels, glInternalFormat, dimensions.width, dimensions.height );
if ( dataReady ) {
state.texSubImage2D( _gl.TEXTURE_2D, 0,
0, 0, glFormat, glType, image );
} else {
state.texImage2D( _gl.TEXTURE_2D, 0,
glInternalFormat, glFormat, glType, image );
if ( textureNeedsGenerateMipmaps( texture ) ) {
generateMipmap( textureType );
sourceProperties.__version = source.version;
textureProperties.__version = texture.version;
state.bindTexture( _gl.TEXTURE_CUBE_MAP,
textureProperties.__webglTexture, _gl.TEXTURE0 + slot );
const workingPrimaries =
ColorManagement.getPrimaries( ColorManagement.workingColorSpace );
const texturePrimaries = texture.colorSpace === NoColorSpace ?
null : ColorManagement.getPrimaries( texture.colorSpace );
const unpackConversion = texture.colorSpace === NoColorSpace ||
workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;
} else {
cubeImage[ i ] = isDataTexture ?
texture.image[ i ].image : texture.image[ i ];
if ( isCompressed ) {
if ( useTexStorage ) {
if ( dataReady ) {
state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0,
mipmap.width, mipmap.height, glFormat, mipmap.data );
} else {
state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j,
glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );
} else {
console.warn( 'THREE.WebGLRenderer:
Attempt to load unsupported compressed texture format in .setTextureCube()' );
} else {
if ( useTexStorage ) {
if ( dataReady ) {
state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0,
mipmap.width, mipmap.height, glFormat, glType, mipmap.data );
}
} else {
} else {
mipmaps = texture.mipmaps;
if ( isDataTexture ) {
if ( useTexStorage ) {
if ( dataReady ) {
} else {
}
for ( let j = 0; j < mipmaps.length; j ++ ) {
if ( useTexStorage ) {
if ( dataReady ) {
state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0,
mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );
} else {
state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1,
glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType,
mipmapImage.data );
} else {
if ( useTexStorage ) {
if ( dataReady ) {
} else {
if ( useTexStorage ) {
if ( dataReady ) {
state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0,
glFormat, glType, mipmap.image[ i ] );
}
} else {
state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1,
glInternalFormat, glFormat, glType, mipmap.image[ i ] );
if ( textureNeedsGenerateMipmaps( texture ) ) {
sourceProperties.__version = source.version;
textureProperties.__version = texture.version;
// Render targets
textureProperties.__renderTarget = renderTarget;
if ( ! renderTargetProperties.__hasExternalTextures ) {
} else {
if ( useMultisampledRTT( renderTarget ) ) {
multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER,
attachment, textureTarget, textureProperties.__webglTexture, 0,
getRenderTargetSamples( renderTarget ) );
if ( renderTarget.depthBuffer ) {
multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER,
samples, glInternalFormat, renderTarget.width, renderTarget.height );
} else if ( isMultisample ) {
_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER,
samples, glInternalFormat, renderTarget.width, renderTarget.height );
} else {
_gl.renderbufferStorage( _gl.RENDERBUFFER,
glInternalFormat, renderTarget.width, renderTarget.height );
} else {
_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER,
samples, glInternalFormat, renderTarget.width, renderTarget.height );
multisampledRTTExt.renderbufferStorageMultisampleEXT(
_gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width,
renderTarget.height );
} else {
_gl.renderbufferStorage( _gl.RENDERBUFFER,
glInternalFormat, renderTarget.width, renderTarget.height );
if ( ! ( renderTarget.depthTexture &&
renderTarget.depthTexture.isDepthTexture ) ) {
renderTarget.depthTexture.image.width = renderTarget.width;
renderTarget.depthTexture.image.height = renderTarget.height;
renderTarget.depthTexture.needsUpdate = true;
setTexture2D( renderTarget.depthTexture, 0 );
if ( useMultisampledRTT( renderTarget ) ) {
multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER,
_gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
} else {
_gl.framebufferTexture2D( _gl.FRAMEBUFFER,
_gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
if ( useMultisampledRTT( renderTarget ) ) {
multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER,
_gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );
} else {
_gl.framebufferTexture2D( _gl.FRAMEBUFFER,
_gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );
} else {
renderTargetProperties.__depthDisposeCallback();
delete renderTargetProperties.__boundDepthTexture;
delete renderTargetProperties.__depthDisposeCallback;
depthTexture.removeEventListener( 'dispose',
disposeEvent );
};
renderTargetProperties.__boundDepthTexture = depthTexture;
}
if ( renderTarget.depthTexture && !
renderTargetProperties.__autoAllocateDepthBuffer ) {
setupDepthTexture( renderTargetProperties.__webglFramebuffer,
renderTarget );
} else {
if ( isCube ) {
renderTargetProperties.__webglDepthbuffer = [];
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglFramebuffer[ i ] );
if ( renderTargetProperties.__webglDepthbuffer[ i ]
=== undefined ) {
renderTargetProperties.__webglDepthbuffer[ i ]
= _gl.createRenderbuffer();
setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ],
renderTarget, false );
} else {
} else {
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglFramebuffer );
if ( renderTargetProperties.__webglDepthbuffer ===
undefined ) {
renderTargetProperties.__webglDepthbuffer =
_gl.createRenderbuffer();
setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer,
renderTarget, false );
} else {
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer,
renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );
setupDepthRenderbuffer( renderTarget );
if ( ! isMultipleRenderTargets ) {
if ( textureProperties.__webglTexture === undefined ) {
textureProperties.__webglTexture = _gl.createTexture();
textureProperties.__version = texture.version;
info.memory.textures ++;
// Setup framebuffer
if ( isCube ) {
renderTargetProperties.__webglFramebuffer = [];
renderTargetProperties.__webglFramebuffer[ i ] = [];
renderTargetProperties.__webglFramebuffer[ i ][
level ] = _gl.createFramebuffer();
} else {
renderTargetProperties.__webglFramebuffer[ i ] =
_gl.createFramebuffer();
} else {
renderTargetProperties.__webglFramebuffer = [];
renderTargetProperties.__webglFramebuffer[ level ] =
_gl.createFramebuffer();
} else {
renderTargetProperties.__webglFramebuffer =
_gl.createFramebuffer();
}
if ( isMultipleRenderTargets ) {
const attachmentProperties =
properties.get( textures[ i ] );
if ( attachmentProperties.__webglTexture ===
undefined ) {
attachmentProperties.__webglTexture =
_gl.createTexture();
info.memory.textures ++;
renderTargetProperties.__webglMultisampledFramebuffer =
_gl.createFramebuffer();
renderTargetProperties.__webglColorRenderbuffer = [];
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglMultisampledFramebuffer );
_gl.bindRenderbuffer( _gl.RENDERBUFFER,
renderTargetProperties.__webglColorRenderbuffer[ i ] );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER,
renderTargetProperties.__webglColorRenderbuffer[ i ] );
}
_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );
if ( renderTarget.depthBuffer ) {
renderTargetProperties.__webglDepthRenderbuffer =
_gl.createRenderbuffer();
setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer,
renderTarget, true );
if ( isCube ) {
state.bindTexture( _gl.TEXTURE_CUBE_MAP,
textureProperties.__webglTexture );
setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ]
[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0,
_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );
} else {
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ],
renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i,
0 );
if ( textureNeedsGenerateMipmaps( texture ) ) {
generateMipmap( _gl.TEXTURE_CUBE_MAP );
state.unbindTexture();
} else if ( isMultipleRenderTargets ) {
state.bindTexture( _gl.TEXTURE_2D,
attachmentProperties.__webglTexture );
setTextureParameters( _gl.TEXTURE_2D, attachment );
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer,
renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );
if ( textureNeedsGenerateMipmaps( attachment ) ) {
generateMipmap( _gl.TEXTURE_2D );
state.unbindTexture();
} else {
if ( renderTarget.isWebGL3DRenderTarget ||
renderTarget.isWebGLArrayRenderTarget ) {
glTextureType = renderTarget.isWebGL3DRenderTarget ?
_gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;
state.bindTexture( glTextureType,
textureProperties.__webglTexture );
setTextureParameters( glTextureType, texture );
} else {
setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer,
renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );
}
if ( textureNeedsGenerateMipmaps( texture ) ) {
generateMipmap( glTextureType );
state.unbindTexture();
if ( renderTarget.depthBuffer ) {
setupDepthRenderbuffer( renderTarget );
if ( textureNeedsGenerateMipmaps( texture ) ) {
if ( renderTarget.samples > 0 ) {
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglMultisampledFramebuffer );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglFramebuffer );
_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );
state.bindFramebuffer( _gl.READ_FRAMEBUFFER,
renderTargetProperties.__webglMultisampledFramebuffer );
state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER,
renderTargetProperties.__webglFramebuffer );
if ( renderTarget.resolveDepthBuffer ) {
if ( renderTarget.depthBuffer ) mask |=
_gl.DEPTH_BUFFER_BIT;
if ( renderTarget.stencilBuffer &&
renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;
if ( isMultipleRenderTargets ) {
const webglTexture =
properties.get( textures[ i ] ).__webglTexture;
_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );
invalidationArrayRead.length = 0;
invalidationArrayDraw.length = 0;
invalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i );
if ( renderTarget.depthBuffer &&
renderTarget.resolveDepthBuffer === false ) {
invalidationArrayRead.push( depthStyle );
invalidationArrayDraw.push( depthStyle );
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglMultisampledFramebuffer );
_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER,
renderTargetProperties.__webglColorRenderbuffer[ i ] );
const webglTexture =
properties.get( textures[ i ] ).__webglTexture;
state.bindFramebuffer( _gl.FRAMEBUFFER,
renderTargetProperties.__webglFramebuffer );
_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );
state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER,
renderTargetProperties.__webglMultisampledFramebuffer );
} else {
if ( renderTarget.depthBuffer &&
renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer ) {
_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER,
[ depthStyle ] );
} else {
return image;
_imageDimensions.width = image.displayWidth;
_imageDimensions.height = image.displayHeight;
} else {
_imageDimensions.width = image.width;
_imageDimensions.height = image.height;
return _imageDimensions;
//
this.allocateTextureUnit = allocateTextureUnit;
this.resetTextureUnits = resetTextureUnits;
this.setTexture2D = setTexture2D;
this.setTexture2DArray = setTexture2DArray;
this.setTexture3D = setTexture3D;
this.setTextureCube = setTextureCube;
this.rebindTextures = rebindTextures;
this.setupRenderTarget = setupRenderTarget;
this.updateRenderTargetMipmap = updateRenderTargetMipmap;
this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
this.setupDepthRenderbuffer = setupDepthRenderbuffer;
this.setupFrameBufferTexture = setupFrameBufferTexture;
this.useMultisampledRTT = useMultisampledRTT;
let extension;
// WebGL2 formats.
// S3TC
} else {
return null;
} else {
} else {
return null;
// PVRTC
} else {
return null;
// ETC
} else {
return null;
// ASTC
} else {
return null;
// BPTC
} else {
return null;
// RGTC
} else {
return null;
//
class WebXRController {
constructor() {
this._targetRay = null;
this._grip = null;
this._hand = null;
getHandSpace() {
this._hand.joints = {};
this._hand.inputState = { pinching: false };
return this._hand;
getTargetRaySpace() {
return this._targetRay;
getGripSpace() {
return this._grip;
}
dispatchEvent( event ) {
this._targetRay.dispatchEvent( event );
this._grip.dispatchEvent( event );
this._hand.dispatchEvent( event );
return this;
connect( inputSource ) {
if ( hand ) {
return this;
disconnect( inputSource ) {
this._targetRay.visible = false;
}
if ( this._grip !== null ) {
this._grip.visible = false;
this._hand.visible = false;
return this;
handPose = true;
joint.matrix.fromArray( jointPose.transform.matrix );
joint.matrix.decompose( joint.position,
joint.rotation, joint.scale );
joint.matrixWorldNeedsUpdate = true;
joint.jointRadius = jointPose.radius;
}
// Custom events
// Check pinchz
const indexTip = hand.joints[ 'index-finger-tip' ];
const thumbTip = hand.joints[ 'thumb-tip' ];
const distance =
indexTip.position.distanceTo( thumbTip.position );
hand.inputState.pinching = false;
this.dispatchEvent( {
type: 'pinchend',
handedness: inputSource.handedness,
target: this
} );
hand.inputState.pinching = true;
this.dispatchEvent( {
type: 'pinchstart',
handedness: inputSource.handedness,
target: this
} );
} else {
grip.matrix.fromArray( gripPose.transform.matrix );
grip.matrix.decompose( grip.position,
grip.rotation, grip.scale );
grip.matrixWorldNeedsUpdate = true;
if ( gripPose.linearVelocity ) {
grip.hasLinearVelocity = true;
grip.linearVelocity.copy( gripPose.linearVelocity );
} else {
grip.hasLinearVelocity = false;
}
if ( gripPose.angularVelocity ) {
grip.hasAngularVelocity = true;
grip.angularVelocity.copy( gripPose.angularVelocity );
} else {
grip.hasAngularVelocity = false;
inputPose = gripPose;
targetRay.matrix.fromArray( inputPose.transform.matrix );
targetRay.matrix.decompose( targetRay.position,
targetRay.rotation, targetRay.scale );
targetRay.matrixWorldNeedsUpdate = true;
if ( inputPose.linearVelocity ) {
targetRay.hasLinearVelocity = true;
targetRay.linearVelocity.copy( inputPose.linearVelocity );
} else {
targetRay.hasLinearVelocity = false;
if ( inputPose.angularVelocity ) {
targetRay.hasAngularVelocity = true;
targetRay.angularVelocity.copy( inputPose.angularVelocity );
} else {
targetRay.hasAngularVelocity = false;
this.dispatchEvent( _moveEvent );
return this;
// private method
hand.add( joint );
const _occlusion_vertex = `
void main() {
gl_Position = vec4( position, 1.0 );
}`;
const _occlusion_fragment = `
uniform sampler2DArray depthColor;
uniform float depthWidth;
uniform float depthHeight;
void main() {
} else {
}`;
class WebXRDepthSensing {
constructor() {
this.texture = null;
this.mesh = null;
this.depthNear = 0;
this.depthFar = 0;
this.depthNear = depthData.depthNear;
this.depthFar = depthData.depthFar;
this.texture = texture;
}
getMesh( cameraXR ) {
return this.mesh;
reset() {
this.texture = null;
this.mesh = null;
getDepthTexture() {
return this.texture;
constructor( renderer, gl ) {
super();
//
//
this.cameraAutoUpdate = true;
this.enabled = false;
this.isPresenting = false;
return controller.getTargetRaySpace();
};
return controller.getGripSpace();
};
return controller.getHandSpace();
};
//
const controllerIndex =
controllerInputSources.indexOf( event.inputSource );
if ( controllerIndex === - 1 ) {
return;
function onSessionEnd() {
session.removeEventListener( 'select', onSessionEvent );
session.removeEventListener( 'selectstart', onSessionEvent );
session.removeEventListener( 'selectend', onSessionEvent );
session.removeEventListener( 'squeeze', onSessionEvent );
session.removeEventListener( 'squeezestart', onSessionEvent );
session.removeEventListener( 'squeezeend', onSessionEvent );
session.removeEventListener( 'end', onSessionEnd );
session.removeEventListener( 'inputsourceschange',
onInputSourcesChange );
controllerInputSources[ i ] = null;
_currentDepthNear = null;
_currentDepthFar = null;
depthSensing.reset();
renderer.setRenderTarget( initialRenderTarget );
glBaseLayer = null;
glProjLayer = null;
glBinding = null;
session = null;
newRenderTarget = null;
//
animation.stop();
scope.isPresenting = false;
renderer.setPixelRatio( currentPixelRatio );
renderer.setSize( currentSize.width, currentSize.height, false );
framebufferScaleFactor = value;
};
referenceSpaceType = value;
};
this.getReferenceSpace = function () {
};
customReferenceSpace = space;
};
this.getBaseLayer = function () {
};
this.getBinding = function () {
return glBinding;
};
this.getFrame = function () {
return xrFrame;
};
this.getSession = function () {
return session;
};
session = value;
await gl.makeXRCompatible();
currentPixelRatio = renderer.getPixelRatio();
renderer.getSize( currentSize );
if ( ! useLayers ) {
const layerInit = {
antialias: attributes.antialias,
alpha: true,
depth: attributes.depth,
stencil: attributes.stencil,
framebufferScaleFactor: framebufferScaleFactor
};
renderer.setPixelRatio( 1 );
renderer.setSize( glBaseLayer.framebufferWidth,
glBaseLayer.framebufferHeight, false );
if ( attributes.depth ) {
glDepthFormat = attributes.stencil ?
gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
depthFormat = attributes.stencil ?
DepthStencilFormat : DepthFormat;
depthType = attributes.stencil ?
UnsignedInt248Type : UnsignedIntType;
const projectionlayerInit = {
colorFormat: gl.RGBA8,
depthFormat: glDepthFormat,
scaleFactor: framebufferScaleFactor
};
glProjLayer =
glBinding.createProjectionLayer( projectionlayerInit );
session.updateRenderState( { layers:
[ glProjLayer ] } );
renderer.setPixelRatio( 1 );
renderer.setSize( glProjLayer.textureWidth,
glProjLayer.textureHeight, false );
this.setFoveation( foveation );
customReferenceSpace = null;
referenceSpace = await
session.requestReferenceSpace( referenceSpaceType );
animation.setContext( session );
animation.start();
scope.isPresenting = true;
};
this.getEnvironmentBlendMode = function () {
return session.environmentBlendMode;
};
this.getDepthTexture = function () {
return depthSensing.getDepthTexture();
};
// Notify disconnected
if ( index >= 0 ) {
// Notify connected
let controllerIndex =
controllerInputSources.indexOf( inputSource );
if ( controllerIndex === - 1 ) {
// Assign input source a controller that currently
has no input source
if ( i >= controllerInputSources.length ) {
controllerInputSources.push( inputSource );
controllerIndex = i;
break;
controllerInputSources[ i ] =
inputSource;
controllerIndex = i;
break;
if ( controller ) {
controller.connect( inputSource );
//
/**
* Assumes 2 cameras that are parallel and share an X-axis, and that
* the cameras' projection and world matrices have already been set.
* And that near and far planes are identical for both cameras.
* Visualization of this technique:
https://computergraphics.stackexchange.com/a/4765
*
* @param {ArrayCamera} camera - The camera to update.
* @param {PerspectiveCamera} cameraL - The left camera.
* @param {PerspectiveCamera} cameraR - The right camera.
*/
function setProjectionFromUnion( camera, cameraL, cameraR ) {
cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );
camera.projectionMatrixInverse.copy( cameraL.projectionMatrixInverse );
} else {
camera.matrixWorld.copy( camera.matrix );
} else {
camera.matrixWorld.multiplyMatrices( parent.matrixWorld,
camera.matrix );
// Note that the new renderState won't apply until the next
frame. See #18320
session.updateRenderState( {
depthNear: cameraXR.near,
depthFar: cameraXR.far
} );
_currentDepthNear = cameraXR.near;
_currentDepthFar = cameraXR.far;
if ( cameras.length === 2 ) {
} else {
cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );
};
camera.matrix.copy( cameraXR.matrixWorld );
} else {
camera.matrix.copy( parent.matrixWorld );
camera.matrix.invert();
camera.matrix.multiply( cameraXR.matrixWorld );
camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );
if ( camera.isPerspectiveCamera ) {
this.getCamera = function () {
return cameraXR;
};
this.getFoveation = function () {
return undefined;
return foveation;
};
foveation = value;
glProjLayer.fixedFoveation = value;
glBaseLayer.fixedFoveation = value;
};
this.hasDepthSensing = function () {
};
this.getDepthSensingMesh = function () {
};
// Animation Loop
renderer.setRenderTargetFramebuffer( newRenderTarget,
glBaseLayer.framebuffer );
renderer.setRenderTarget( newRenderTarget );
cameraXR.cameras.length = 0;
cameraXRNeedsUpdate = true;
} else {
const glSubImage =
glBinding.getViewSubImage( glProjLayer, view );
viewport = glSubImage.viewport;
renderer.setRenderTargetTextures(
newRenderTarget,
glSubImage.colorTexture,
glProjLayer.ignoreDepthValues ?
undefined : glSubImage.depthStencilTexture );
renderer.setRenderTarget( newRenderTarget
);
camera.matrix.fromArray( view.transform.matrix );
camera.matrix.decompose( camera.position,
camera.quaternion, camera.scale );
camera.projectionMatrix.fromArray( view.projectionMatrix );
if ( i === 0 ) {
cameraXR.matrix.copy( camera.matrix );
cameraXR.matrix.decompose( cameraXR.position,
cameraXR.quaternion, cameraXR.scale );
cameraXR.cameras.push( camera );
//
const depthData =
glBinding.getDepthInformation( views[ 0 ] );
//
if ( frame.detectedPlanes ) {
xrFrame = null;
animation.setAnimationLoop( onAnimationFrame );
onAnimationFrameCallback = callback;
};
map.updateMatrix();
uniform.value.copy( map.matrix );
fog.color.getRGB( uniforms.fogColor.value,
getUnlitUniformColorSpace( renderer ) );
if ( fog.isFog ) {
uniforms.fogNear.value = fog.near;
uniforms.fogFar.value = fog.far;
} else if ( fog.isFogExp2 ) {
uniforms.fogDensity.value = fog.density;
if ( material.isMeshBasicMaterial ) {
} else if ( material.isMeshLambertMaterial ) {
} else if ( material.isMeshToonMaterial ) {
} else if ( material.isMeshPhongMaterial ) {
if ( material.isMeshPhysicalMaterial ) {
} else if ( material.isMeshMatcapMaterial ) {
} else if ( material.isMeshDepthMaterial ) {
} else if ( material.isMeshDistanceMaterial ) {
} else if ( material.isMeshNormalMaterial ) {
} else if ( material.isLineBasicMaterial ) {
if ( material.isLineDashedMaterial ) {
} else if ( material.isPointsMaterial ) {
} else if ( material.isSpriteMaterial ) {
} else if ( material.isShadowMaterial ) {
uniforms.color.value.copy( material.color );
uniforms.opacity.value = material.opacity;
} else if ( material.isShaderMaterial ) {
}
}
uniforms.opacity.value = material.opacity;
if ( material.color ) {
uniforms.diffuse.value.copy( material.color );
if ( material.emissive ) {
if ( material.map ) {
uniforms.map.value = material.map;
if ( material.alphaMap ) {
uniforms.alphaMap.value = material.alphaMap;
refreshTransformUniform( material.alphaMap,
uniforms.alphaMapTransform );
if ( material.bumpMap ) {
uniforms.bumpMap.value = material.bumpMap;
refreshTransformUniform( material.bumpMap,
uniforms.bumpMapTransform );
uniforms.bumpScale.value = material.bumpScale;
uniforms.bumpScale.value *= - 1;
if ( material.normalMap ) {
uniforms.normalMap.value = material.normalMap;
refreshTransformUniform( material.normalMap,
uniforms.normalMapTransform );
uniforms.normalScale.value.copy( material.normalScale );
uniforms.normalScale.value.negate();
if ( material.displacementMap ) {
uniforms.displacementMap.value = material.displacementMap;
refreshTransformUniform( material.displacementMap,
uniforms.displacementMapTransform );
uniforms.displacementScale.value = material.displacementScale;
uniforms.displacementBias.value = material.displacementBias;
if ( material.emissiveMap ) {
uniforms.emissiveMap.value = material.emissiveMap;
refreshTransformUniform( material.emissiveMap,
uniforms.emissiveMapTransform );
if ( material.specularMap ) {
uniforms.specularMap.value = material.specularMap;
refreshTransformUniform( material.specularMap,
uniforms.specularMapTransform );
if ( material.alphaTest > 0 ) {
uniforms.alphaTest.value = material.alphaTest;
if ( envMap ) {
uniforms.envMap.value = envMap;
_e1.copy( envMapRotation );
// accommodate left-handed frame
_e1.x *= - 1; _e1.y *= - 1; _e1.z *= - 1;
uniforms.reflectivity.value = material.reflectivity;
uniforms.ior.value = material.ior;
uniforms.refractionRatio.value = material.refractionRatio;
if ( material.lightMap ) {
uniforms.lightMap.value = material.lightMap;
uniforms.lightMapIntensity.value = material.lightMapIntensity;
refreshTransformUniform( material.lightMap,
uniforms.lightMapTransform );
if ( material.aoMap ) {
uniforms.aoMap.value = material.aoMap;
uniforms.aoMapIntensity.value = material.aoMapIntensity;
refreshTransformUniform( material.aoMap,
uniforms.aoMapTransform );
uniforms.diffuse.value.copy( material.color );
uniforms.opacity.value = material.opacity;
if ( material.map ) {
uniforms.map.value = material.map;
uniforms.dashSize.value = material.dashSize;
uniforms.totalSize.value = material.dashSize + material.gapSize;
uniforms.scale.value = material.scale;
uniforms.diffuse.value.copy( material.color );
uniforms.opacity.value = material.opacity;
uniforms.size.value = material.size * pixelRatio;
uniforms.scale.value = height * 0.5;
if ( material.map ) {
uniforms.map.value = material.map;
if ( material.alphaMap ) {
uniforms.alphaMap.value = material.alphaMap;
refreshTransformUniform( material.alphaMap,
uniforms.alphaMapTransform );
if ( material.alphaTest > 0 ) {
uniforms.alphaTest.value = material.alphaTest;
uniforms.diffuse.value.copy( material.color );
uniforms.opacity.value = material.opacity;
uniforms.rotation.value = material.rotation;
if ( material.map ) {
uniforms.map.value = material.map;
if ( material.alphaMap ) {
uniforms.alphaMap.value = material.alphaMap;
refreshTransformUniform( material.alphaMap,
uniforms.alphaMapTransform );
if ( material.alphaTest > 0 ) {
uniforms.alphaTest.value = material.alphaTest;
uniforms.specular.value.copy( material.specular );
uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to
prevent pow( 0.0, 0.0 )
if ( material.gradientMap ) {
uniforms.gradientMap.value = material.gradientMap;
uniforms.metalness.value = material.metalness;
if ( material.metalnessMap ) {
uniforms.metalnessMap.value = material.metalnessMap;
refreshTransformUniform( material.metalnessMap,
uniforms.metalnessMapTransform );
uniforms.roughness.value = material.roughness;
if ( material.roughnessMap ) {
uniforms.roughnessMap.value = material.roughnessMap;
refreshTransformUniform( material.roughnessMap,
uniforms.roughnessMapTransform );
if ( material.envMap ) {
//uniforms.envMap.value = material.envMap; // part of uniforms
common
uniforms.envMapIntensity.value = material.envMapIntensity;
if ( material.sheen > 0 ) {
uniforms.sheenRoughness.value = material.sheenRoughness;
if ( material.sheenColorMap ) {
uniforms.sheenColorMap.value = material.sheenColorMap;
refreshTransformUniform( material.sheenColorMap,
uniforms.sheenColorMapTransform );
if ( material.sheenRoughnessMap ) {
uniforms.sheenRoughnessMap.value =
material.sheenRoughnessMap;
refreshTransformUniform( material.sheenRoughnessMap,
uniforms.sheenRoughnessMapTransform );
if ( material.clearcoat > 0 ) {
uniforms.clearcoat.value = material.clearcoat;
uniforms.clearcoatRoughness.value = material.clearcoatRoughness;
if ( material.clearcoatMap ) {
uniforms.clearcoatMap.value = material.clearcoatMap;
refreshTransformUniform( material.clearcoatMap,
uniforms.clearcoatMapTransform );
}
if ( material.clearcoatRoughnessMap ) {
uniforms.clearcoatRoughnessMap.value =
material.clearcoatRoughnessMap;
refreshTransformUniform( material.clearcoatRoughnessMap,
uniforms.clearcoatRoughnessMapTransform );
if ( material.clearcoatNormalMap ) {
uniforms.clearcoatNormalMap.value =
material.clearcoatNormalMap;
refreshTransformUniform( material.clearcoatNormalMap,
uniforms.clearcoatNormalMapTransform );
uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );
uniforms.clearcoatNormalScale.value.negate();
if ( material.dispersion > 0 ) {
uniforms.dispersion.value = material.dispersion;
if ( material.iridescence > 0 ) {
uniforms.iridescence.value = material.iridescence;
uniforms.iridescenceIOR.value = material.iridescenceIOR;
uniforms.iridescenceThicknessMinimum.value =
material.iridescenceThicknessRange[ 0 ];
uniforms.iridescenceThicknessMaximum.value =
material.iridescenceThicknessRange[ 1 ];
if ( material.iridescenceMap ) {
uniforms.iridescenceMap.value = material.iridescenceMap;
refreshTransformUniform( material.iridescenceMap,
uniforms.iridescenceMapTransform );
if ( material.iridescenceThicknessMap ) {
uniforms.iridescenceThicknessMap.value =
material.iridescenceThicknessMap;
refreshTransformUniform( material.iridescenceThicknessMap,
uniforms.iridescenceThicknessMapTransform );
if ( material.transmission > 0 ) {
uniforms.transmission.value = material.transmission;
uniforms.transmissionSamplerMap.value =
transmissionRenderTarget.texture;
uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width,
transmissionRenderTarget.height );
if ( material.transmissionMap ) {
uniforms.transmissionMap.value = material.transmissionMap;
refreshTransformUniform( material.transmissionMap,
uniforms.transmissionMapTransform );
uniforms.thickness.value = material.thickness;
if ( material.thicknessMap ) {
uniforms.thicknessMap.value = material.thicknessMap;
refreshTransformUniform( material.thicknessMap,
uniforms.thicknessMapTransform );
uniforms.attenuationDistance.value =
material.attenuationDistance;
uniforms.attenuationColor.value.copy( material.attenuationColor );
if ( material.anisotropy > 0 ) {
uniforms.anisotropyVector.value.set( material.anisotropy *
Math.cos( material.anisotropyRotation ), material.anisotropy *
Math.sin( material.anisotropyRotation ) );
if ( material.anisotropyMap ) {
uniforms.anisotropyMap.value = material.anisotropyMap;
refreshTransformUniform( material.anisotropyMap,
uniforms.anisotropyMapTransform );
}
}
uniforms.specularIntensity.value = material.specularIntensity;
uniforms.specularColor.value.copy( material.specularColor );
if ( material.specularColorMap ) {
uniforms.specularColorMap.value = material.specularColorMap;
refreshTransformUniform( material.specularColorMap,
uniforms.specularColorMapTransform );
if ( material.specularIntensityMap ) {
uniforms.specularIntensityMap.value =
material.specularIntensityMap;
refreshTransformUniform( material.specularIntensityMap,
uniforms.specularIntensityMapTransform );
if ( material.matcap ) {
uniforms.matcap.value = material.matcap;
uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );
uniforms.nearDistance.value = light.shadow.camera.near;
uniforms.farDistance.value = light.shadow.camera.far;
return {
refreshFogUniforms: refreshFogUniforms,
refreshMaterialUniforms: refreshMaterialUniforms
};
prepareUniformsGroup( uniformsGroup );
uniformsGroup.addEventListener( 'dispose',
onUniformsGroupsDispose );
updateBufferData( uniformsGroup );
return buffer;
function allocateBindingPointIndex() {
if ( allocatedBindingPoints.indexOf( i ) === - 1 ) {
allocatedBindingPoints.push( i );
return i;
return 0;
let arrayOffset = 0;
uniform.__data[ 0 ] = value;
gl.bufferSubData( gl.UNIFORM_BUFFER,
offset + arrayOffset, uniform.__data );
} else if ( value.isMatrix3 ) {
uniform.__data[ 0 ] =
value.elements[ 0 ];
uniform.__data[ 1 ] =
value.elements[ 1 ];
uniform.__data[ 2 ] =
value.elements[ 2 ];
uniform.__data[ 3 ] = 0;
uniform.__data[ 4 ] =
value.elements[ 3 ];
uniform.__data[ 5 ] =
value.elements[ 4 ];
uniform.__data[ 6 ] =
value.elements[ 5 ];
uniform.__data[ 7 ] = 0;
uniform.__data[ 8 ] =
value.elements[ 6 ];
uniform.__data[ 9 ] =
value.elements[ 7 ];
uniform.__data[ 10 ] =
value.elements[ 8 ];
uniform.__data[ 11 ] = 0;
} else {
value.toArray( uniform.__data,
arrayOffset );
arrayOffset += info.storage /
Float32Array.BYTES_PER_ELEMENT;
} else {
return true;
} else {
} else {
cachedObject.copy( value );
return true;
return false;
offset += chunkPadding;
//
uniformsGroup.__size = offset;
uniformsGroup.__cache = {};
return this;
const info = {
boundary: 0, // bytes
storage: 0 // bytes
};
// float/int/bool
info.boundary = 4;
info.storage = 4;
} else if ( value.isVector2 ) {
// vec2
info.boundary = 8;
info.storage = 8;
// vec3
info.boundary = 16;
info.storage = 12; // evil: vec3 must start on a 16-byte boundary
but it only consumes 12 bytes
} else if ( value.isVector4 ) {
// vec4
info.boundary = 16;
info.storage = 16;
} else if ( value.isMatrix3 ) {
info.boundary = 48;
info.storage = 48;
} else if ( value.isMatrix4 ) {
// mat4
info.boundary = 64;
info.storage = 64;
} else if ( value.isTexture ) {
} else {
return info;
uniformsGroup.removeEventListener( 'dispose',
onUniformsGroupsDispose );
const index =
allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );
allocatedBindingPoints.splice( index, 1 );
function dispose() {
gl.deleteBuffer( buffers[ id ] );
allocatedBindingPoints = [];
buffers = {};
updateList = {};
return {
bind: bind,
update: update,
dispose: dispose
};
class WebGLRenderer {
constructor( parameters = {} ) {
const {
canvas = createCanvasElement(),
context = null,
depth = true,
stencil = false,
alpha = false,
antialias = false,
premultipliedAlpha = true,
preserveDrawingBuffer = false,
powerPreference = 'default',
failIfMajorPerformanceCaveat = false,
reverseDepthBuffer = false,
} = parameters;
this.isWebGLRenderer = true;
let _alpha;
_alpha = context.getContextAttributes().alpha;
} else {
_alpha = alpha;
// public properties
this.domElement = canvas;
/**
* Enables error checking and reporting when shader programs are
being compiled
* @type {boolean}
*/
checkShaderErrors: true,
/**
* Callback for custom error reporting.
* @type {?Function}
*/
onShaderError: null
};
// clearing
this.autoClear = true;
this.autoClearColor = true;
this.autoClearDepth = true;
this.autoClearStencil = true;
// scene graph
this.sortObjects = true;
// user-defined clipping
this.clippingPlanes = [];
this.localClippingEnabled = false;
this._outputColorSpace = SRGBColorSpace;
// tone mapping
this.toneMapping = NoToneMapping;
this.toneMappingExposure = 1.0;
// internal properties
let _currentActiveCubeFace = 0;
let _currentActiveMipmapLevel = 0;
let _currentRenderTarget = null;
let _currentMaterialId = - 1;
let _currentCamera = null;
//
let _pixelRatio = 1;
let _opaqueSort = null;
let _transparentSort = null;
// frustum
// clipping
function getTargetPixelRatio() {
// initialize
try {
const contextAttributes = {
alpha: true,
depth,
stencil,
antialias,
premultipliedAlpha,
preserveDrawingBuffer,
powerPreference,
failIfMajorPerformanceCaveat,
};
if ( getContext( contextName ) ) {
} else {
} catch ( error ) {
function initGLContext() {
state.buffers.depth.setReversed( true );
info.programs = programCache.programs;
_this.capabilities = capabilities;
_this.extensions = extensions;
_this.properties = properties;
_this.renderLists = renderLists;
_this.shadowMap = shadowMap;
_this.state = state;
_this.info = info;
initGLContext();
// xr
this.xr = xr;
// API
this.getContext = function () {
return _gl;
};
this.getContextAttributes = function () {
return _gl.getContextAttributes();
};
this.forceContextLoss = function () {
};
this.forceContextRestore = function () {
};
this.getPixelRatio = function () {
return _pixelRatio;
};
_pixelRatio = value;
};
};
if ( xr.isPresenting ) {
_width = width;
_height = height;
};
};
_width = width;
_height = height;
_pixelRatio = pixelRatio;
};
};
if ( x.isVector4 ) {
} else {
};
};
if ( x.isVector4 ) {
} else {
};
this.getScissorTest = function () {
return _scissorTest;
};
};
_opaqueSort = method;
};
_transparentSort = method;
};
// Clearing
};
this.setClearColor = function () {
};
this.getClearAlpha = function () {
return background.getClearAlpha();
};
this.setClearAlpha = function () {
};
let bits = 0;
if ( color ) {
if ( isUnsignedType ) {
uintClearColor[ 0 ] = r;
uintClearColor[ 1 ] = g;
uintClearColor[ 2 ] = b;
uintClearColor[ 3 ] = a;
_gl.clearBufferuiv( _gl.COLOR, 0,
uintClearColor );
} else {
intClearColor[ 0 ] = r;
intClearColor[ 1 ] = g;
intClearColor[ 2 ] = b;
intClearColor[ 3 ] = a;
_gl.clearBufferiv( _gl.COLOR, 0,
intClearColor );
} else {
bits |= _gl.COLOR_BUFFER_BIT;
if ( depth ) {
bits |= _gl.DEPTH_BUFFER_BIT;
if ( stencil ) {
bits |= _gl.STENCIL_BUFFER_BIT;
this.state.buffers.stencil.setMask( 0xffffffff );
_gl.clear( bits );
};
this.clearColor = function () {
};
this.clearDepth = function () {
};
this.clearStencil = function () {
};
//
this.dispose = function () {
background.dispose();
renderLists.dispose();
renderStates.dispose();
properties.dispose();
cubemaps.dispose();
cubeuvmaps.dispose();
objects.dispose();
bindingStates.dispose();
uniformsGroups.dispose();
programCache.dispose();
xr.dispose();
animation.stop();
};
// Events
event.preventDefault();
_isContextLost = true;
_isContextLost = false;
initGLContext();
info.autoReset = infoAutoReset;
shadowMap.enabled = shadowMapEnabled;
shadowMap.autoUpdate = shadowMapAutoUpdate;
shadowMap.needsUpdate = shadowMapNeedsUpdate;
shadowMap.type = shadowMapType;
deallocateMaterial( material );
// Buffer deallocation
function deallocateMaterial( material ) {
releaseMaterialProgramReferences( material );
properties.remove( material );
programCache.releaseProgram( program );
} );
if ( material.isShaderMaterial ) {
programCache.releaseShaderCache( material );
// Buffer rendering
//
rangeFactor = 2;
}
//
//
let attribute;
let renderer = bufferRenderer;
renderer = indexedBufferRenderer;
renderer.setIndex( attribute );
//
if ( object.isMesh ) {
} else {
renderer.setMode( _gl.TRIANGLES );
} else if ( object.isLine ) {
if ( object.isLineSegments ) {
renderer.setMode( _gl.LINES );
} else if ( object.isLineLoop ) {
renderer.setMode( _gl.LINE_LOOP );
} else {
renderer.setMode( _gl.LINE_STRIP );
} else if ( object.isPoints ) {
renderer.setMode( _gl.POINTS );
} else if ( object.isSprite ) {
renderer.setMode( _gl.TRIANGLES );
if ( object.isBatchedMesh ) {
renderer.renderMultiDrawInstances( object._multiDrawStarts,
object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );
} else {
if ( ! extensions.get( 'WEBGL_multi_draw' ) ) {
} else {
} else if ( object.isInstancedMesh ) {
} else if ( geometry.isInstancedBufferGeometry ) {
} else {
};
// Compile
material.side = BackSide;
material.needsUpdate = true;
getProgram( material, scene, object );
material.side = FrontSide;
material.needsUpdate = true;
getProgram( material, scene, object );
material.side = DoubleSide;
} else {
renderStateStack.push( currentRenderState );
// gather lights from both the target scene and the new object
that will be added to the scene.
if ( object.isLight &&
object.layers.test( camera.layers ) ) {
currentRenderState.pushLight( object );
if ( object.castShadow ) {
currentRenderState.pushShadow( object );
} );
if ( object.isLight &&
object.layers.test( camera.layers ) ) {
currentRenderState.pushLight( object );
if ( object.castShadow ) {
currentRenderState.pushShadow( object );
} );
}
currentRenderState.setupLights();
return;
if ( material ) {
if ( Array.isArray( material ) ) {
} else {
} );
renderStateStack.pop();
currentRenderState = null;
return materials;
};
// compileAsync
function checkMaterialsReady() {
const materialProperties =
properties.get( material );
const program =
materialProperties.currentProgram;
if ( program.isReady() ) {
} );
if ( materials.size === 0 ) {
resolve( scene );
return;
setTimeout( checkMaterialsReady, 10 );
checkMaterialsReady();
} else {
setTimeout( checkMaterialsReady, 10 );
}
} );
};
// Animation Loop
function onXRSessionStart() {
animation.stop();
function onXRSessionEnd() {
animation.start();
onAnimationFrameCallback = callback;
xr.setAnimationLoop( callback );
};
// Rendering
//
if ( scene.isScene === true ) scene.onBeforeRender( _this, scene,
camera, _currentRenderTarget );
renderStateStack.push( currentRenderState );
_projScreenMatrix.multiplyMatrices( camera.projectionMatrix,
camera.matrixWorldInverse );
_frustum.setFromProjectionMatrix( _projScreenMatrix );
_localClippingEnabled = this.localClippingEnabled;
_clippingEnabled = clipping.init( this.clippingPlanes,
_localClippingEnabled );
renderListStack.push( currentRenderList );
//
this.info.render.frame ++;
//
// render scene
currentRenderState.setupLights();
if ( camera.isArrayCamera ) {
if ( transmissiveObjects.length > 0 ) {
renderTransmissionPass( opaqueObjects,
transmissiveObjects, scene, camera2 );
} else {
if ( transmissiveObjects.length > 0 )
renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );
//
textures.updateMultisampleRenderTarget( _currentRenderTarget );
textures.updateRenderTargetMipmap( _currentRenderTarget );
//
// _gl.finish();
bindingStates.resetDefaultState();
_currentMaterialId = - 1;
_currentCamera = null;
renderStateStack.pop();
if ( renderStateStack.length > 0 ) {
currentRenderState =
renderStateStack[ renderStateStack.length - 1 ];
} else {
currentRenderState = null;
renderListStack.pop();
if ( renderListStack.length > 0 ) {
} else {
currentRenderList = null;
};
if ( visible ) {
if ( object.isGroup ) {
groupOrder = object.renderOrder;
} else if ( object.isLOD ) {
} else if ( object.isLight ) {
currentRenderState.pushLight( object );
if ( object.castShadow ) {
currentRenderState.pushShadow( object );
} else if ( object.isSprite ) {
if ( ! object.frustumCulled ||
_frustum.intersectsSprite( object ) ) {
if ( sortObjects ) {
_vector4.setFromMatrixPosition( object.matrixWorld )
.applyMatrix4( _projScreenMatrix );
}
const geometry = objects.update( object );
const material = object.material;
if ( material.visible ) {
if ( ! object.frustumCulled ||
_frustum.intersectsObject( object ) ) {
if ( sortObjects ) {
if ( object.boundingSphere !==
undefined ) {
_vector4.copy( object.boundingSphere.center );
} else {
if ( geometry.boundingSphere ===
null ) geometry.computeBoundingSphere();
_vector4.copy( geometry.boundingSphere.center );
_vector4
.applyMatrix4( object.matrixWorld )
.applyMatrix4( _projScreenMatrix );
if ( Array.isArray( material ) ) {
if ( groupMaterial &&
groupMaterial.visible ) {
} else if ( material.visible ) {
currentRenderState.setupLightsView( camera );
state.buffers.depth.setTest( true );
state.buffers.depth.setMask( true );
state.buffers.color.setMask( true );
state.setPolygonOffset( false );
return;
if ( currentRenderState.state.transmissionRenderTarget[ camera.id
] === undefined ) {
// debug
/*
const geometry = new PlaneGeometry();
const material = new MeshBasicMaterial( { map:
_transmissionRenderTarget.texture } );
const transmissionRenderTarget =
currentRenderState.state.transmissionRenderTarget[ camera.id ];
//
const currentRenderTarget = _this.getRenderTarget();
_this.setRenderTarget( transmissionRenderTarget );
_this.getClearColor( _currentClearColor );
_currentClearAlpha = _this.getClearAlpha();
if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff,
0.5 );
_this.clear();
// Turn off the features which can affect the frag color for
opaque objects pass.
// Otherwise they are applied twice in opaque objects pass and
transmission objects pass.
const currentToneMapping = _this.toneMapping;
_this.toneMapping = NoToneMapping;
currentRenderState.setupLightsView( camera );
textures.updateMultisampleRenderTarget( transmissionRenderTarget );
textures.updateRenderTargetMipmap( transmissionRenderTarget );
material.side = BackSide;
material.needsUpdate = true;
material.side = currentSide;
material.needsUpdate = true;
renderTargetNeedsUpdate = true;
textures.updateMultisampleRenderTarget( transmissionRenderTarget );
textures.updateRenderTargetMipmap( transmissionRenderTarget );
_this.setRenderTarget( currentRenderTarget );
_this.toneMapping = currentToneMapping;
if ( object.layers.test( camera.layers ) ) {
}
}
object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse,
object.matrixWorld );
object.normalMatrix.getNormalMatrix( object.modelViewMatrix );
material.side = BackSide;
material.needsUpdate = true;
_this.renderBufferDirect( camera, scene, geometry,
material, object, group );
material.side = FrontSide;
material.needsUpdate = true;
_this.renderBufferDirect( camera, scene, geometry,
material, object, group );
material.side = DoubleSide;
} else {
materialProperties.environment =
material.isMeshStandardMaterial ? scene.environment : null;
materialProperties.fog = scene.fog;
materialProperties.envMap = ( material.isMeshStandardMaterial ?
cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
materialProperties.envMapRotation =
( materialProperties.environment !== null && material.envMap === null ) ?
scene.environmentRotation : material.envMapRotation;
// new material
updateCommonMaterialProperties( material,
parameters );
return program;
} else {
materialProperties.uniforms = parameters.uniforms;
uniforms.clippingPlanes = clipping.uniform;
if ( materialProperties.needsLights ) {
uniforms.ambientLightColor.value = lights.state.ambient;
uniforms.lightProbe.value = lights.state.probe;
uniforms.directionalLights.value =
lights.state.directional;
uniforms.directionalLightShadows.value =
lights.state.directionalShadow;
uniforms.spotLights.value = lights.state.spot;
uniforms.spotLightShadows.value = lights.state.spotShadow;
uniforms.rectAreaLights.value = lights.state.rectArea;
uniforms.ltc_1.value = lights.state.rectAreaLTC1;
uniforms.ltc_2.value = lights.state.rectAreaLTC2;
uniforms.pointLights.value = lights.state.point;
uniforms.pointLightShadows.value =
lights.state.pointShadow;
uniforms.hemisphereLights.value = lights.state.hemi;
uniforms.directionalShadowMap.value =
lights.state.directionalShadowMap;
uniforms.directionalShadowMatrix.value =
lights.state.directionalShadowMatrix;
uniforms.spotShadowMap.value = lights.state.spotShadowMap;
uniforms.spotLightMatrix.value =
lights.state.spotLightMatrix;
uniforms.spotLightMap.value = lights.state.spotLightMap;
uniforms.pointShadowMap.value =
lights.state.pointShadowMap;
uniforms.pointShadowMatrix.value =
lights.state.pointShadowMatrix;
// TODO (abelnation): add area lights shadow info to
uniforms
materialProperties.currentProgram = program;
materialProperties.uniformsList = null;
return program;
const progUniforms =
materialProperties.currentProgram.getUniforms();
materialProperties.uniformsList =
WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );
return materialProperties.uniformsList;
materialProperties.outputColorSpace =
parameters.outputColorSpace;
materialProperties.batching = parameters.batching;
materialProperties.batchingColor = parameters.batchingColor;
materialProperties.instancing = parameters.instancing;
materialProperties.instancingColor = parameters.instancingColor;
materialProperties.instancingMorph = parameters.instancingMorph;
materialProperties.skinning = parameters.skinning;
materialProperties.morphTargets = parameters.morphTargets;
materialProperties.morphNormals = parameters.morphNormals;
materialProperties.morphColors = parameters.morphColors;
materialProperties.morphTargetsCount =
parameters.morphTargetsCount;
materialProperties.numClippingPlanes =
parameters.numClippingPlanes;
materialProperties.numIntersection =
parameters.numClipIntersection;
materialProperties.vertexAlphas = parameters.vertexAlphas;
materialProperties.vertexTangents = parameters.vertexTangents;
materialProperties.toneMapping = parameters.toneMapping;
textures.resetTextureUnits();
if ( material.toneMapped ) {
toneMapping = _this.toneMapping;
const useCache =
camera === _currentCamera &&
material.id === _currentMaterialId;
//
if ( materialProperties.needsLights &&
( materialProperties.lightsStateVersion !== lights.state.version ) ) {
needsProgramChange = true;
} else if ( materialProperties.outputColorSpace !==
colorSpace ) {
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
} else if ( object.isInstancedMesh &&
materialProperties.instancingMorph === false && object.morphTexture !== null ) {
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
needsProgramChange = true;
}
} else {
needsProgramChange = true;
materialProperties.__version = material.version;
//
if ( state.useProgram( program.program ) ) {
refreshProgram = true;
refreshMaterial = true;
refreshLights = true;
_currentMaterialId = material.id;
refreshMaterial = true;
const reverseDepthBuffer =
state.buffers.depth.getReversed();
if ( reverseDepthBuffer ) {
_currentProjectionMatrix.copy( camera.projectionMatrix );
toNormalizedProjectionMatrix( _currentProjectionMatrix );
toReversedProjectionMatrix( _currentProjectionMatrix );
p_uniforms.setValue( _gl, 'projectionMatrix',
_currentProjectionMatrix );
} else {
uCamPos.setValue( _gl,
_vector3.setFromMatrixPosition( camera.matrixWorld ) );
if ( capabilities.logarithmicDepthBuffer ) {
if ( material.isMeshPhongMaterial ||
material.isMeshToonMaterial ||
material.isMeshLambertMaterial ||
material.isMeshBasicMaterial ||
material.isMeshStandardMaterial ||
material.isShaderMaterial ) {
_currentCamera = camera;
if ( object.isSkinnedMesh ) {
if ( skeleton ) {
if ( object.isBatchedMesh ) {
materialProperties.receiveShadow = object.receiveShadow;
p_uniforms.setValue( _gl, 'receiveShadow',
object.receiveShadow );
// https://github.com/mrdoob/three.js/pull/24467#issuecomment-
1209031512
m_uniforms.envMap.value = envMap;
m_uniforms.envMapIntensity.value =
scene.environmentIntensity;
if ( refreshMaterial ) {
if ( materialProperties.needsLights ) {
markUniformsLightsNeedsUpdate( m_uniforms,
refreshLights );
WebGLUniforms.upload( _gl,
getUniformList( materialProperties ), m_uniforms, textures );
WebGLUniforms.upload( _gl,
getUniformList( materialProperties ), m_uniforms, textures );
material.uniformsNeedUpdate = false;
if ( material.isSpriteMaterial ) {
// common matrices
// UBOs
if ( material.isShaderMaterial || material.isRawShaderMaterial )
{
return program;
}
// If uniforms are marked as clean, they don't need to be loaded to the
GPU.
uniforms.ambientLightColor.needsUpdate = value;
uniforms.lightProbe.needsUpdate = value;
uniforms.directionalLights.needsUpdate = value;
uniforms.directionalLightShadows.needsUpdate = value;
uniforms.pointLights.needsUpdate = value;
uniforms.pointLightShadows.needsUpdate = value;
uniforms.spotLights.needsUpdate = value;
uniforms.spotLightShadows.needsUpdate = value;
uniforms.rectAreaLights.needsUpdate = value;
uniforms.hemisphereLights.needsUpdate = value;
return material.isMeshLambertMaterial ||
material.isMeshToonMaterial || material.isMeshPhongMaterial ||
material.isMeshStandardMaterial ||
material.isShadowMaterial ||
( material.isShaderMaterial && material.lights === true );
this.getActiveCubeFace = function () {
return _currentActiveCubeFace;
};
this.getActiveMipmapLevel = function () {
return _currentActiveMipmapLevel;
};
this.getRenderTarget = function () {
return _currentRenderTarget;
};
if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {
};
};
_currentRenderTarget = renderTarget;
_currentActiveCubeFace = activeCubeFace;
_currentActiveMipmapLevel = activeMipmapLevel;
if ( renderTarget ) {
if ( renderTargetProperties.__useDefaultFramebuffer !==
undefined ) {
} else if ( renderTargetProperties.__hasExternalTextures )
{
} else if ( renderTarget.depthBuffer ) {
textures.setupDepthRenderbuffer( renderTarget );
if ( texture.isData3DTexture || texture.isDataArrayTexture
|| texture.isCompressedArrayTexture ) {
isRenderTarget3D = true;
const __webglFramebuffer =
properties.get( renderTarget ).__webglFramebuffer;
if ( renderTarget.isWebGLCubeRenderTarget ) {
if
( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {
framebuffer =
__webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];
} else {
framebuffer =
__webglFramebuffer[ activeCubeFace ];
isCube = true;
framebuffer =
properties.get( renderTarget ).__webglMultisampledFramebuffer;
} else {
if ( Array.isArray( __webglFramebuffer ) ) {
framebuffer =
__webglFramebuffer[ activeMipmapLevel ];
} else {
framebuffer = __webglFramebuffer;
_currentViewport.copy( renderTarget.viewport );
_currentScissor.copy( renderTarget.scissor );
_currentScissorTest = renderTarget.scissorTest;
} else {
framebuffer = _scratchFrameBuffer;
state.viewport( _currentViewport );
state.scissor( _currentScissor );
state.setScissorTest( _currentScissorTest );
if ( isCube ) {
const textureProperties =
properties.get( renderTarget.texture );
_gl.framebufferTexture2D( _gl.FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace,
textureProperties.__webglTexture, activeMipmapLevel );
} else if ( isRenderTarget3D ) {
const textureProperties =
properties.get( renderTarget.texture );
const layer = activeCubeFace;
_gl.framebufferTextureLayer( _gl.FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel,
layer );
};
console.error( 'THREE.WebGLRenderer.readRenderTargetPixels:
renderTarget is not THREE.WebGLRenderTarget.' );
return;
let framebuffer =
properties.get( renderTarget ).__webglFramebuffer;
if ( renderTarget.isWebGLCubeRenderTarget &&
activeCubeFaceIndex !== undefined ) {
if ( framebuffer ) {
try {
if ( !
capabilities.textureFormatReadable( textureFormat ) ) {
if ( !
capabilities.textureTypeReadable( textureType ) ) {
} finally {
};
throw new
Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not
THREE.WebGLRenderTarget.' );
let framebuffer =
properties.get( renderTarget ).__webglFramebuffer;
if ( renderTarget.isWebGLCubeRenderTarget &&
activeCubeFaceIndex !== undefined ) {
if ( framebuffer ) {
if ( !
capabilities.textureFormatReadable( textureFormat ) ) {
throw new
Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in
RGBA or implementation defined format.' );
if ( ! capabilities.textureTypeReadable( textureType ) ) {
throw new
Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in
UnsignedByteType or implementation defined type.' );
_gl.flush();
return buffer;
} else {
throw new
Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are
out of range.' );
};
// @deprecated, r165
warnOnce( 'WebGLRenderer: copyFramebufferToTexture function
signature has changed.' );
textures.setTexture2D( texture, 0 );
state.unbindTexture();
};
// @deprecated, r165
warnOnce( 'WebGLRenderer: copyTextureToTexture function
signature has changed.' );
if ( srcLevel !== 0 ) {
// @deprecated, r171
warnOnce( 'WebGLRenderer: copyTextureToTexture
function signature has changed to support src and dst mipmap levels.' );
dstLevel = srcLevel;
srcLevel = 0;
} else {
dstLevel = 0;
} else {
depth = image.depth;
} else if ( srcTexture.isData3DTexture ) {
} else {
depth = 1;
minX = 0;
minY = 0;
minZ = 0;
dstX = dstPosition.x;
dstY = dstPosition.y;
dstZ = dstPosition.z;
} else {
dstX = 0;
dstY = 0;
dstZ = 0;
if ( dstTexture.isData3DTexture ) {
textures.setTexture3D( dstTexture, 0 );
glTarget = _gl.TEXTURE_3D;
} else if ( dstTexture.isDataArrayTexture ||
dstTexture.isCompressedArrayTexture ) {
textures.setTexture2DArray( dstTexture, 0 );
glTarget = _gl.TEXTURE_2D_ARRAY;
} else {
textures.setTexture2D( dstTexture, 0 );
glTarget = _gl.TEXTURE_2D;
} else {
_gl.framebufferTexture2D( _gl.READ_FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, srcTextureProperties.__webglTexture,
srcLevel );
if ( isDst3D ) {
} else {
_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER,
_gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, dstTextureProperties.__webglTexture,
dstLevel );
} else if ( isDst3D ) {
} else {
} else {
if ( isDst3D ) {
} else if ( dstTexture.isCompressedArrayTexture ) {
_gl.compressedTexSubImage3D( glTarget,
dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );
} else {
} else {
} else if ( srcTexture.isCompressedTexture ) {
_gl.compressedTexSubImage2D( _gl.TEXTURE_2D,
dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data );
} else {
// reset values
_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT,
currentUnpackImageHeight );
_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS,
currentUnpackSkipPixels );
_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES,
currentUnpackSkipImages );
_gl.generateMipmap( glTarget );
state.unbindTexture();
};
// @deprecated, r165
warnOnce( 'WebGLRenderer: copyTextureToTexture3D function
signature has changed.' );
// @deprecated, r170
warnOnce( 'WebGLRenderer: copyTextureToTexture3D function has
been deprecated. Use "copyTextureToTexture" instead.' );
};
textures.setupRenderTarget( target );
};
if ( texture.isCubeTexture ) {
textures.setTextureCube( texture, 0 );
} else if ( texture.isData3DTexture ) {
textures.setTexture3D( texture, 0 );
} else if ( texture.isDataArrayTexture ||
texture.isCompressedArrayTexture ) {
textures.setTexture2DArray( texture, 0 );
} else {
textures.setTexture2D( texture, 0 );
state.unbindTexture();
};
this.resetState = function () {
_currentActiveCubeFace = 0;
_currentActiveMipmapLevel = 0;
_currentRenderTarget = null;
state.reset();
bindingStates.reset();
};
get coordinateSystem() {
return WebGLCoordinateSystem;
get outputColorSpace() {
return this._outputColorSpace;
this._outputColorSpace = colorSpace;
const gl = this.getContext();
gl.drawingBufferColorspace =
ColorManagement._getDrawingBufferColorSpace( colorSpace );
gl.unpackColorSpace = ColorManagement._getUnpackColorSpace();
exports.ACESFilmicToneMapping = ACESFilmicToneMapping;
exports.AddEquation = AddEquation;
exports.AddOperation = AddOperation;
exports.AdditiveAnimationBlendMode = AdditiveAnimationBlendMode;
exports.AdditiveBlending = AdditiveBlending;
exports.AgXToneMapping = AgXToneMapping;
exports.AlphaFormat = AlphaFormat;
exports.AlwaysCompare = AlwaysCompare;
exports.AlwaysDepth = AlwaysDepth;
exports.AlwaysStencilFunc = AlwaysStencilFunc;
exports.AmbientLight = AmbientLight;
exports.AnimationAction = AnimationAction;
exports.AnimationClip = AnimationClip;
exports.AnimationLoader = AnimationLoader;
exports.AnimationMixer = AnimationMixer;
exports.AnimationObjectGroup = AnimationObjectGroup;
exports.AnimationUtils = AnimationUtils;
exports.ArcCurve = ArcCurve;
exports.ArrayCamera = ArrayCamera;
exports.ArrowHelper = ArrowHelper;
exports.AttachedBindMode = AttachedBindMode;
exports.Audio = Audio;
exports.AudioAnalyser = AudioAnalyser;
exports.AudioContext = AudioContext;
exports.AudioListener = AudioListener;
exports.AudioLoader = AudioLoader;
exports.AxesHelper = AxesHelper;
exports.BackSide = BackSide;
exports.BasicDepthPacking = BasicDepthPacking;
exports.BasicShadowMap = BasicShadowMap;
exports.BatchedMesh = BatchedMesh;
exports.Bone = Bone;
exports.BooleanKeyframeTrack = BooleanKeyframeTrack;
exports.Box2 = Box2;
exports.Box3 = Box3;
exports.Box3Helper = Box3Helper;
exports.BoxGeometry = BoxGeometry;
exports.BoxHelper = BoxHelper;
exports.BufferAttribute = BufferAttribute;
exports.BufferGeometry = BufferGeometry;
exports.BufferGeometryLoader = BufferGeometryLoader;
exports.ByteType = ByteType;
exports.Cache = Cache;
exports.Camera = Camera;
exports.CameraHelper = CameraHelper;
exports.CanvasTexture = CanvasTexture;
exports.CapsuleGeometry = CapsuleGeometry;
exports.CatmullRomCurve3 = CatmullRomCurve3;
exports.CineonToneMapping = CineonToneMapping;
exports.CircleGeometry = CircleGeometry;
exports.ClampToEdgeWrapping = ClampToEdgeWrapping;
exports.Clock = Clock;
exports.Color = Color;
exports.ColorKeyframeTrack = ColorKeyframeTrack;
exports.ColorManagement = ColorManagement;
exports.CompressedArrayTexture = CompressedArrayTexture;
exports.CompressedCubeTexture = CompressedCubeTexture;
exports.CompressedTexture = CompressedTexture;
exports.CompressedTextureLoader = CompressedTextureLoader;
exports.ConeGeometry = ConeGeometry;
exports.ConstantAlphaFactor = ConstantAlphaFactor;
exports.ConstantColorFactor = ConstantColorFactor;
exports.Controls = Controls;
exports.CubeCamera = CubeCamera;
exports.CubeReflectionMapping = CubeReflectionMapping;
exports.CubeRefractionMapping = CubeRefractionMapping;
exports.CubeTexture = CubeTexture;
exports.CubeTextureLoader = CubeTextureLoader;
exports.CubeUVReflectionMapping = CubeUVReflectionMapping;
exports.CubicBezierCurve = CubicBezierCurve;
exports.CubicBezierCurve3 = CubicBezierCurve3;
exports.CubicInterpolant = CubicInterpolant;
exports.CullFaceBack = CullFaceBack;
exports.CullFaceFront = CullFaceFront;
exports.CullFaceFrontBack = CullFaceFrontBack;
exports.CullFaceNone = CullFaceNone;
exports.Curve = Curve;
exports.CurvePath = CurvePath;
exports.CustomBlending = CustomBlending;
exports.CustomToneMapping = CustomToneMapping;
exports.CylinderGeometry = CylinderGeometry;
exports.Cylindrical = Cylindrical;
exports.Data3DTexture = Data3DTexture;
exports.DataArrayTexture = DataArrayTexture;
exports.DataTexture = DataTexture;
exports.DataTextureLoader = DataTextureLoader;
exports.DataUtils = DataUtils;
exports.DecrementStencilOp = DecrementStencilOp;
exports.DecrementWrapStencilOp = DecrementWrapStencilOp;
exports.DefaultLoadingManager = DefaultLoadingManager;
exports.DepthFormat = DepthFormat;
exports.DepthStencilFormat = DepthStencilFormat;
exports.DepthTexture = DepthTexture;
exports.DetachedBindMode = DetachedBindMode;
exports.DirectionalLight = DirectionalLight;
exports.DirectionalLightHelper = DirectionalLightHelper;
exports.DiscreteInterpolant = DiscreteInterpolant;
exports.DodecahedronGeometry = DodecahedronGeometry;
exports.DoubleSide = DoubleSide;
exports.DstAlphaFactor = DstAlphaFactor;
exports.DstColorFactor = DstColorFactor;
exports.DynamicCopyUsage = DynamicCopyUsage;
exports.DynamicDrawUsage = DynamicDrawUsage;
exports.DynamicReadUsage = DynamicReadUsage;
exports.EdgesGeometry = EdgesGeometry;
exports.EllipseCurve = EllipseCurve;
exports.EqualCompare = EqualCompare;
exports.EqualDepth = EqualDepth;
exports.EqualStencilFunc = EqualStencilFunc;
exports.EquirectangularReflectionMapping = EquirectangularReflectionMapping;
exports.EquirectangularRefractionMapping = EquirectangularRefractionMapping;
exports.Euler = Euler;
exports.EventDispatcher = EventDispatcher;
exports.ExtrudeGeometry = ExtrudeGeometry;
exports.FileLoader = FileLoader;
exports.Float16BufferAttribute = Float16BufferAttribute;
exports.Float32BufferAttribute = Float32BufferAttribute;
exports.FloatType = FloatType;
exports.Fog = Fog;
exports.FogExp2 = FogExp2;
exports.FramebufferTexture = FramebufferTexture;
exports.FrontSide = FrontSide;
exports.Frustum = Frustum;
exports.GLBufferAttribute = GLBufferAttribute;
exports.GLSL1 = GLSL1;
exports.GLSL3 = GLSL3;
exports.GreaterCompare = GreaterCompare;
exports.GreaterDepth = GreaterDepth;
exports.GreaterEqualCompare = GreaterEqualCompare;
exports.GreaterEqualDepth = GreaterEqualDepth;
exports.GreaterEqualStencilFunc = GreaterEqualStencilFunc;
exports.GreaterStencilFunc = GreaterStencilFunc;
exports.GridHelper = GridHelper;
exports.Group = Group;
exports.HalfFloatType = HalfFloatType;
exports.HemisphereLight = HemisphereLight;
exports.HemisphereLightHelper = HemisphereLightHelper;
exports.IcosahedronGeometry = IcosahedronGeometry;
exports.ImageBitmapLoader = ImageBitmapLoader;
exports.ImageLoader = ImageLoader;
exports.ImageUtils = ImageUtils;
exports.IncrementStencilOp = IncrementStencilOp;
exports.IncrementWrapStencilOp = IncrementWrapStencilOp;
exports.InstancedBufferAttribute = InstancedBufferAttribute;
exports.InstancedBufferGeometry = InstancedBufferGeometry;
exports.InstancedInterleavedBuffer = InstancedInterleavedBuffer;
exports.InstancedMesh = InstancedMesh;
exports.Int16BufferAttribute = Int16BufferAttribute;
exports.Int32BufferAttribute = Int32BufferAttribute;
exports.Int8BufferAttribute = Int8BufferAttribute;
exports.IntType = IntType;
exports.InterleavedBuffer = InterleavedBuffer;
exports.InterleavedBufferAttribute = InterleavedBufferAttribute;
exports.Interpolant = Interpolant;
exports.InterpolateDiscrete = InterpolateDiscrete;
exports.InterpolateLinear = InterpolateLinear;
exports.InterpolateSmooth = InterpolateSmooth;
exports.InvertStencilOp = InvertStencilOp;
exports.KeepStencilOp = KeepStencilOp;
exports.KeyframeTrack = KeyframeTrack;
exports.LOD = LOD;
exports.LatheGeometry = LatheGeometry;
exports.Layers = Layers;
exports.LessCompare = LessCompare;
exports.LessDepth = LessDepth;
exports.LessEqualCompare = LessEqualCompare;
exports.LessEqualDepth = LessEqualDepth;
exports.LessEqualStencilFunc = LessEqualStencilFunc;
exports.LessStencilFunc = LessStencilFunc;
exports.Light = Light;
exports.LightProbe = LightProbe;
exports.Line = Line;
exports.Line3 = Line3;
exports.LineBasicMaterial = LineBasicMaterial;
exports.LineCurve = LineCurve;
exports.LineCurve3 = LineCurve3;
exports.LineDashedMaterial = LineDashedMaterial;
exports.LineLoop = LineLoop;
exports.LineSegments = LineSegments;
exports.LinearFilter = LinearFilter;
exports.LinearInterpolant = LinearInterpolant;
exports.LinearMipMapLinearFilter = LinearMipMapLinearFilter;
exports.LinearMipMapNearestFilter = LinearMipMapNearestFilter;
exports.LinearMipmapLinearFilter = LinearMipmapLinearFilter;
exports.LinearMipmapNearestFilter = LinearMipmapNearestFilter;
exports.LinearSRGBColorSpace = LinearSRGBColorSpace;
exports.LinearToneMapping = LinearToneMapping;
exports.LinearTransfer = LinearTransfer;
exports.Loader = Loader;
exports.LoaderUtils = LoaderUtils;
exports.LoadingManager = LoadingManager;
exports.LoopOnce = LoopOnce;
exports.LoopPingPong = LoopPingPong;
exports.LoopRepeat = LoopRepeat;
exports.LuminanceAlphaFormat = LuminanceAlphaFormat;
exports.LuminanceFormat = LuminanceFormat;
exports.MOUSE = MOUSE;
exports.Material = Material;
exports.MaterialLoader = MaterialLoader;
exports.MathUtils = MathUtils;
exports.Matrix2 = Matrix2;
exports.Matrix3 = Matrix3;
exports.Matrix4 = Matrix4;
exports.MaxEquation = MaxEquation;
exports.Mesh = Mesh;
exports.MeshBasicMaterial = MeshBasicMaterial;
exports.MeshDepthMaterial = MeshDepthMaterial;
exports.MeshDistanceMaterial = MeshDistanceMaterial;
exports.MeshLambertMaterial = MeshLambertMaterial;
exports.MeshMatcapMaterial = MeshMatcapMaterial;
exports.MeshNormalMaterial = MeshNormalMaterial;
exports.MeshPhongMaterial = MeshPhongMaterial;
exports.MeshPhysicalMaterial = MeshPhysicalMaterial;
exports.MeshStandardMaterial = MeshStandardMaterial;
exports.MeshToonMaterial = MeshToonMaterial;
exports.MinEquation = MinEquation;
exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
exports.MixOperation = MixOperation;
exports.MultiplyBlending = MultiplyBlending;
exports.MultiplyOperation = MultiplyOperation;
exports.NearestFilter = NearestFilter;
exports.NearestMipMapLinearFilter = NearestMipMapLinearFilter;
exports.NearestMipMapNearestFilter = NearestMipMapNearestFilter;
exports.NearestMipmapLinearFilter = NearestMipmapLinearFilter;
exports.NearestMipmapNearestFilter = NearestMipmapNearestFilter;
exports.NeutralToneMapping = NeutralToneMapping;
exports.NeverCompare = NeverCompare;
exports.NeverDepth = NeverDepth;
exports.NeverStencilFunc = NeverStencilFunc;
exports.NoBlending = NoBlending;
exports.NoColorSpace = NoColorSpace;
exports.NoToneMapping = NoToneMapping;
exports.NormalAnimationBlendMode = NormalAnimationBlendMode;
exports.NormalBlending = NormalBlending;
exports.NotEqualCompare = NotEqualCompare;
exports.NotEqualDepth = NotEqualDepth;
exports.NotEqualStencilFunc = NotEqualStencilFunc;
exports.NumberKeyframeTrack = NumberKeyframeTrack;
exports.Object3D = Object3D;
exports.ObjectLoader = ObjectLoader;
exports.ObjectSpaceNormalMap = ObjectSpaceNormalMap;
exports.OctahedronGeometry = OctahedronGeometry;
exports.OneFactor = OneFactor;
exports.OneMinusConstantAlphaFactor = OneMinusConstantAlphaFactor;
exports.OneMinusConstantColorFactor = OneMinusConstantColorFactor;
exports.OneMinusDstAlphaFactor = OneMinusDstAlphaFactor;
exports.OneMinusDstColorFactor = OneMinusDstColorFactor;
exports.OneMinusSrcAlphaFactor = OneMinusSrcAlphaFactor;
exports.OneMinusSrcColorFactor = OneMinusSrcColorFactor;
exports.OrthographicCamera = OrthographicCamera;
exports.PCFShadowMap = PCFShadowMap;
exports.PCFSoftShadowMap = PCFSoftShadowMap;
exports.PMREMGenerator = PMREMGenerator;
exports.Path = Path;
exports.PerspectiveCamera = PerspectiveCamera;
exports.Plane = Plane;
exports.PlaneGeometry = PlaneGeometry;
exports.PlaneHelper = PlaneHelper;
exports.PointLight = PointLight;
exports.PointLightHelper = PointLightHelper;
exports.Points = Points;
exports.PointsMaterial = PointsMaterial;
exports.PolarGridHelper = PolarGridHelper;
exports.PolyhedronGeometry = PolyhedronGeometry;
exports.PositionalAudio = PositionalAudio;
exports.PropertyBinding = PropertyBinding;
exports.PropertyMixer = PropertyMixer;
exports.QuadraticBezierCurve = QuadraticBezierCurve;
exports.QuadraticBezierCurve3 = QuadraticBezierCurve3;
exports.Quaternion = Quaternion;
exports.QuaternionKeyframeTrack = QuaternionKeyframeTrack;
exports.QuaternionLinearInterpolant = QuaternionLinearInterpolant;
exports.RED_GREEN_RGTC2_Format = RED_GREEN_RGTC2_Format;
exports.RED_RGTC1_Format = RED_RGTC1_Format;
exports.REVISION = REVISION;
exports.RGBADepthPacking = RGBADepthPacking;
exports.RGBAFormat = RGBAFormat;
exports.RGBAIntegerFormat = RGBAIntegerFormat;
exports.RGBA_ASTC_10x10_Format = RGBA_ASTC_10x10_Format;
exports.RGBA_ASTC_10x5_Format = RGBA_ASTC_10x5_Format;
exports.RGBA_ASTC_10x6_Format = RGBA_ASTC_10x6_Format;
exports.RGBA_ASTC_10x8_Format = RGBA_ASTC_10x8_Format;
exports.RGBA_ASTC_12x10_Format = RGBA_ASTC_12x10_Format;
exports.RGBA_ASTC_12x12_Format = RGBA_ASTC_12x12_Format;
exports.RGBA_ASTC_4x4_Format = RGBA_ASTC_4x4_Format;
exports.RGBA_ASTC_5x4_Format = RGBA_ASTC_5x4_Format;
exports.RGBA_ASTC_5x5_Format = RGBA_ASTC_5x5_Format;
exports.RGBA_ASTC_6x5_Format = RGBA_ASTC_6x5_Format;
exports.RGBA_ASTC_6x6_Format = RGBA_ASTC_6x6_Format;
exports.RGBA_ASTC_8x5_Format = RGBA_ASTC_8x5_Format;
exports.RGBA_ASTC_8x6_Format = RGBA_ASTC_8x6_Format;
exports.RGBA_ASTC_8x8_Format = RGBA_ASTC_8x8_Format;
exports.RGBA_BPTC_Format = RGBA_BPTC_Format;
exports.RGBA_ETC2_EAC_Format = RGBA_ETC2_EAC_Format;
exports.RGBA_PVRTC_2BPPV1_Format = RGBA_PVRTC_2BPPV1_Format;
exports.RGBA_PVRTC_4BPPV1_Format = RGBA_PVRTC_4BPPV1_Format;
exports.RGBA_S3TC_DXT1_Format = RGBA_S3TC_DXT1_Format;
exports.RGBA_S3TC_DXT3_Format = RGBA_S3TC_DXT3_Format;
exports.RGBA_S3TC_DXT5_Format = RGBA_S3TC_DXT5_Format;
exports.RGBDepthPacking = RGBDepthPacking;
exports.RGBFormat = RGBFormat;
exports.RGBIntegerFormat = RGBIntegerFormat;
exports.RGB_BPTC_SIGNED_Format = RGB_BPTC_SIGNED_Format;
exports.RGB_BPTC_UNSIGNED_Format = RGB_BPTC_UNSIGNED_Format;
exports.RGB_ETC1_Format = RGB_ETC1_Format;
exports.RGB_ETC2_Format = RGB_ETC2_Format;
exports.RGB_PVRTC_2BPPV1_Format = RGB_PVRTC_2BPPV1_Format;
exports.RGB_PVRTC_4BPPV1_Format = RGB_PVRTC_4BPPV1_Format;
exports.RGB_S3TC_DXT1_Format = RGB_S3TC_DXT1_Format;
exports.RGDepthPacking = RGDepthPacking;
exports.RGFormat = RGFormat;
exports.RGIntegerFormat = RGIntegerFormat;
exports.RawShaderMaterial = RawShaderMaterial;
exports.Ray = Ray;
exports.Raycaster = Raycaster;
exports.RectAreaLight = RectAreaLight;
exports.RedFormat = RedFormat;
exports.RedIntegerFormat = RedIntegerFormat;
exports.ReinhardToneMapping = ReinhardToneMapping;
exports.RenderTarget = RenderTarget;
exports.RenderTarget3D = RenderTarget3D;
exports.RenderTargetArray = RenderTargetArray;
exports.RepeatWrapping = RepeatWrapping;
exports.ReplaceStencilOp = ReplaceStencilOp;
exports.ReverseSubtractEquation = ReverseSubtractEquation;
exports.RingGeometry = RingGeometry;
exports.SIGNED_RED_GREEN_RGTC2_Format = SIGNED_RED_GREEN_RGTC2_Format;
exports.SIGNED_RED_RGTC1_Format = SIGNED_RED_RGTC1_Format;
exports.SRGBColorSpace = SRGBColorSpace;
exports.SRGBTransfer = SRGBTransfer;
exports.Scene = Scene;
exports.ShaderChunk = ShaderChunk;
exports.ShaderLib = ShaderLib;
exports.ShaderMaterial = ShaderMaterial;
exports.ShadowMaterial = ShadowMaterial;
exports.Shape = Shape;
exports.ShapeGeometry = ShapeGeometry;
exports.ShapePath = ShapePath;
exports.ShapeUtils = ShapeUtils;
exports.ShortType = ShortType;
exports.Skeleton = Skeleton;
exports.SkeletonHelper = SkeletonHelper;
exports.SkinnedMesh = SkinnedMesh;
exports.Source = Source;
exports.Sphere = Sphere;
exports.SphereGeometry = SphereGeometry;
exports.Spherical = Spherical;
exports.SphericalHarmonics3 = SphericalHarmonics3;
exports.SplineCurve = SplineCurve;
exports.SpotLight = SpotLight;
exports.SpotLightHelper = SpotLightHelper;
exports.Sprite = Sprite;
exports.SpriteMaterial = SpriteMaterial;
exports.SrcAlphaFactor = SrcAlphaFactor;
exports.SrcAlphaSaturateFactor = SrcAlphaSaturateFactor;
exports.SrcColorFactor = SrcColorFactor;
exports.StaticCopyUsage = StaticCopyUsage;
exports.StaticDrawUsage = StaticDrawUsage;
exports.StaticReadUsage = StaticReadUsage;
exports.StereoCamera = StereoCamera;
exports.StreamCopyUsage = StreamCopyUsage;
exports.StreamDrawUsage = StreamDrawUsage;
exports.StreamReadUsage = StreamReadUsage;
exports.StringKeyframeTrack = StringKeyframeTrack;
exports.SubtractEquation = SubtractEquation;
exports.SubtractiveBlending = SubtractiveBlending;
exports.TOUCH = TOUCH;
exports.TangentSpaceNormalMap = TangentSpaceNormalMap;
exports.TetrahedronGeometry = TetrahedronGeometry;
exports.Texture = Texture;
exports.TextureLoader = TextureLoader;
exports.TextureUtils = TextureUtils;
exports.TorusGeometry = TorusGeometry;
exports.TorusKnotGeometry = TorusKnotGeometry;
exports.Triangle = Triangle;
exports.TriangleFanDrawMode = TriangleFanDrawMode;
exports.TriangleStripDrawMode = TriangleStripDrawMode;
exports.TrianglesDrawMode = TrianglesDrawMode;
exports.TubeGeometry = TubeGeometry;
exports.UVMapping = UVMapping;
exports.Uint16BufferAttribute = Uint16BufferAttribute;
exports.Uint32BufferAttribute = Uint32BufferAttribute;
exports.Uint8BufferAttribute = Uint8BufferAttribute;
exports.Uint8ClampedBufferAttribute = Uint8ClampedBufferAttribute;
exports.Uniform = Uniform;
exports.UniformsGroup = UniformsGroup;
exports.UniformsLib = UniformsLib;
exports.UniformsUtils = UniformsUtils;
exports.UnsignedByteType = UnsignedByteType;
exports.UnsignedInt248Type = UnsignedInt248Type;
exports.UnsignedInt5999Type = UnsignedInt5999Type;
exports.UnsignedIntType = UnsignedIntType;
exports.UnsignedShort4444Type = UnsignedShort4444Type;
exports.UnsignedShort5551Type = UnsignedShort5551Type;
exports.UnsignedShortType = UnsignedShortType;
exports.VSMShadowMap = VSMShadowMap;
exports.Vector2 = Vector2;
exports.Vector3 = Vector3;
exports.Vector4 = Vector4;
exports.VectorKeyframeTrack = VectorKeyframeTrack;
exports.VideoFrameTexture = VideoFrameTexture;
exports.VideoTexture = VideoTexture;
exports.WebGL3DRenderTarget = WebGL3DRenderTarget;
exports.WebGLArrayRenderTarget = WebGLArrayRenderTarget;
exports.WebGLCoordinateSystem = WebGLCoordinateSystem;
exports.WebGLCubeRenderTarget = WebGLCubeRenderTarget;
exports.WebGLRenderTarget = WebGLRenderTarget;
exports.WebGLRenderer = WebGLRenderer;
exports.WebGLUtils = WebGLUtils;
exports.WebGPUCoordinateSystem = WebGPUCoordinateSystem;
exports.WireframeGeometry = WireframeGeometry;
exports.WrapAroundEnding = WrapAroundEnding;
exports.ZeroCurvatureEnding = ZeroCurvatureEnding;
exports.ZeroFactor = ZeroFactor;
exports.ZeroSlopeEnding = ZeroSlopeEnding;
exports.ZeroStencilOp = ZeroStencilOp;
exports.createCanvasElement = createCanvasElement;