From 1e11bd3eb2001417c766eb85535f65d5a6081659 Mon Sep 17 00:00:00 2001 From: Jose Ferrao Date: Wed, 3 Jan 2024 07:58:13 +0000 Subject: [PATCH] Use map controls --- examples/basic.js | 15819 +++++++++++++++++-------------- examples/providers.js | 15829 ++++++++++++++++++-------------- examples/transition.js | 15813 +++++++++++++++++-------------- package.json | 4 +- source/examples/basic.ts | 2 +- source/examples/providers.ts | 2 +- source/examples/transition.ts | 2 +- 7 files changed, 26593 insertions(+), 20878 deletions(-) diff --git a/examples/basic.js b/examples/basic.js index f6b7b07..f038f03 100644 --- a/examples/basic.js +++ b/examples/basic.js @@ -3,10 +3,11 @@ /** * @license - * Copyright 2010-2022 Three.js Authors + * Copyright 2010-2023 Three.js Authors * SPDX-License-Identifier: MIT */ - const REVISION = '147'; + const REVISION = '160'; + const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; const CullFaceNone = 0; @@ -40,6 +41,10 @@ const DstColorFactor = 208; const OneMinusDstColorFactor = 209; const SrcAlphaSaturateFactor = 210; + const ConstantColorFactor = 211; + const OneMinusConstantColorFactor = 212; + const ConstantAlphaFactor = 213; + const OneMinusConstantAlphaFactor = 214; const NeverDepth = 0; const AlwaysDepth = 1; const LessDepth = 2; @@ -57,6 +62,7 @@ const CineonToneMapping = 3; const ACESFilmicToneMapping = 4; const CustomToneMapping = 5; + const AgXToneMapping = 6; const UVMapping = 300; const CubeReflectionMapping = 301; @@ -85,7 +91,6 @@ const UnsignedShort5551Type = 1018; const UnsignedInt248Type = 1020; const AlphaFormat = 1021; - const RGBFormat = 1022; // @deprecated since r137 const RGBAFormat = 1023; const LuminanceFormat = 1024; const LuminanceAlphaFormat = 1025; @@ -123,22 +128,53 @@ const RGBA_ASTC_12x10_Format = 37820; const RGBA_ASTC_12x12_Format = 37821; const RGBA_BPTC_Format = 36492; + const RGB_BPTC_SIGNED_Format = 36494; + const RGB_BPTC_UNSIGNED_Format = 36495; + const RED_RGTC1_Format = 36283; + const SIGNED_RED_RGTC1_Format = 36284; + const RED_GREEN_RGTC2_Format = 36285; + const SIGNED_RED_GREEN_RGTC2_Format = 36286; + /** @deprecated Use LinearSRGBColorSpace or NoColorSpace in three.js r152+. */ const LinearEncoding = 3000; + /** @deprecated Use SRGBColorSpace in three.js r152+. */ const sRGBEncoding = 3001; const BasicDepthPacking = 3200; const RGBADepthPacking = 3201; const TangentSpaceNormalMap = 0; const ObjectSpaceNormalMap = 1; + + // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. + const NoColorSpace = ''; const SRGBColorSpace = 'srgb'; const LinearSRGBColorSpace = 'srgb-linear'; + const DisplayP3ColorSpace = 'display-p3'; + const LinearDisplayP3ColorSpace = 'display-p3-linear'; + + const LinearTransfer = 'linear'; + const SRGBTransfer = 'srgb'; + + const Rec709Primaries = 'rec709'; + const P3Primaries = 'p3'; const KeepStencilOp = 7680; const AlwaysStencilFunc = 519; + const NeverCompare = 512; + const LessCompare = 513; + const EqualCompare = 514; + const LessEqualCompare = 515; + const GreaterCompare = 516; + const NotEqualCompare = 517; + const GreaterEqualCompare = 518; + const AlwaysCompare = 519; + const StaticDrawUsage = 35044; const GLSL3 = '300 es'; const _SRGBAFormat = 1035; // fallback for WebGL 1 + const WebGLCoordinateSystem = 2000; + const WebGPUCoordinateSystem = 2001; + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -226,6 +262,8 @@ 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' ]; + let _seed = 1234567; + const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; @@ -261,6 +299,28 @@ } + // Linear mapping from range to range + function mapLinear( x, a1, a2, b1, b2 ) { + + 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 ) { @@ -268,18 +328,167 @@ } + // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ + function damp( x, y, lambda, dt ) { + + return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); + + } + + // https://www.desmos.com/calculator/vcsjnyz7x4 + function pingpong( x, length = 1 ) { + + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); + + } + + // http://en.wikipedia.org/wiki/Smoothstep + function smoothstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + + } + + function smootherstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + + } + + // Random integer from interval + function randInt( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + } + + // Random float from interval + function randFloat( low, high ) { + + return low + Math.random() * ( high - low ); + + } + + // Random float from <-range/2, range/2> interval + function randFloatSpread( range ) { + + return range * ( 0.5 - Math.random() ); + + } + + // Deterministic pseudo-random float in the interval [ 0, 1 ] + function seededRandom( s ) { + + if ( s !== undefined ) _seed = s; + + // Mulberry32 generator + + let t = _seed += 0x6D2B79F5; + + t = Math.imul( t ^ t >>> 15, t | 1 ); + + t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); + + return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; + + } + + function degToRad( degrees ) { + + return degrees * DEG2RAD; + + } + + function radToDeg( radians ) { + + return radians * RAD2DEG; + + } + function isPowerOfTwo( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } + function ceilPowerOfTwo( value ) { + + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + + } + function floorPowerOfTwo( value ) { return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); } + function setQuaternionFromProperEuler( q, a, b, c, order ) { + + // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles + + // rotations are applied to the axes in the order specified by 'order' + // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' + // angles are in radians + + const cos = Math.cos; + const sin = Math.sin; + + const c2 = cos( b / 2 ); + const s2 = sin( b / 2 ); + + const c13 = cos( ( a + c ) / 2 ); + const s13 = sin( ( a + c ) / 2 ); + + const c1_3 = cos( ( a - c ) / 2 ); + const s1_3 = sin( ( a - c ) / 2 ); + + const c3_1 = cos( ( c - a ) / 2 ); + const s3_1 = sin( ( c - a ) / 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 ); + + } + + } + function denormalize( value, array ) { switch ( array.constructor ) { @@ -288,6 +497,10 @@ return value; + case Uint32Array: + + return value / 4294967295.0; + case Uint16Array: return value / 65535.0; @@ -296,6 +509,10 @@ return value / 255.0; + case Int32Array: + + return Math.max( value / 2147483647.0, - 1.0 ); + case Int16Array: return Math.max( value / 32767.0, - 1.0 ); @@ -320,6 +537,10 @@ return value; + case Uint32Array: + + return Math.round( value * 4294967295.0 ); + case Uint16Array: return Math.round( value * 65535.0 ); @@ -328,6 +549,10 @@ return Math.round( value * 255.0 ); + case Int32Array: + + return Math.round( value * 2147483647.0 ); + case Int16Array: return Math.round( value * 32767.0 ); @@ -344,6 +569,33 @@ } + 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 ) { @@ -637,8 +889,8 @@ roundToZero() { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); return this; @@ -699,6 +951,20 @@ } + angleTo( v ) { + + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + + if ( denominator === 0 ) return Math.PI / 2; + + const theta = this.dot( v ) / denominator; + + // clamp, to handle numerical problems + + return Math.acos( clamp( theta, - 1, 1 ) ); + + } + distanceTo( v ) { return Math.sqrt( this.distanceToSquared( v ) ); @@ -809,7 +1075,7 @@ class Matrix3 { - constructor() { + constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { Matrix3.prototype.isMatrix3 = true; @@ -821,6 +1087,12 @@ ]; + if ( n11 !== undefined ) { + + this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); + + } + } set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { @@ -1070,13 +1342,27 @@ makeTranslation( x, y ) { - this.set( + if ( x.isVector2 ) { - 1, 0, x, - 0, 1, y, - 0, 0, 1 + 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; @@ -1194,3538 +1480,3548 @@ } - function SRGBToLinear( c ) { + function createCanvasElement() { - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + const canvas = createElementNS( 'canvas' ); + canvas.style.display = 'block'; + return canvas; } - function LinearToSRGB( c ) { + const _cache = {}; - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + function warnOnce( message ) { + + if ( message in _cache ) return; + + _cache[ message ] = true; + + console.warn( message ); } - // JavaScript RGB-to-RGB transforms, defined as - // FN[InputColorSpace][OutputColorSpace] callback functions. - const FN = { - [ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear }, - [ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB }, + /** + * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping + * or clipping. Based on W3C specifications for sRGB and Display P3, + * and ICC specifications for the D50 connection space. Values in/out + * are _linear_ sRGB and _linear_ Display P3. + * + * Note that both sRGB and Display P3 use the sRGB transfer functions. + * + * Reference: + * - http://www.russellcottrell.com/photo/matrixCalculator.htm + */ + + const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( + 0.8224621, 0.177538, 0.0, + 0.0331941, 0.9668058, 0.0, + 0.0170827, 0.0723974, 0.9105199, + ); + + const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( + 1.2249401, - 0.2249404, 0.0, + - 0.0420569, 1.0420571, 0.0, + - 0.0196376, - 0.0786361, 1.0982735 + ); + + /** + * Defines supported color spaces by transfer function and primaries, + * and provides conversions to/from the Linear-sRGB reference space. + */ + const COLOR_SPACES = { + [ LinearSRGBColorSpace ]: { + transfer: LinearTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color, + fromReference: ( color ) => color, + }, + [ SRGBColorSpace ]: { + transfer: SRGBTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color.convertSRGBToLinear(), + fromReference: ( color ) => color.convertLinearToSRGB(), + }, + [ LinearDisplayP3ColorSpace ]: { + transfer: LinearTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), + }, + [ DisplayP3ColorSpace ]: { + transfer: SRGBTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), + }, }; + const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); + const ColorManagement = { - legacyMode: true, + enabled: true, + + _workingColorSpace: LinearSRGBColorSpace, get workingColorSpace() { - return LinearSRGBColorSpace; + return this._workingColorSpace; }, set workingColorSpace( colorSpace ) { - console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' ); + if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { + + throw new Error( `Unsupported working color space, "${ colorSpace }".` ); + + } + + this._workingColorSpace = colorSpace; }, convert: function ( color, sourceColorSpace, targetColorSpace ) { - if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { + if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { return color; } - if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) { + const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; + const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; - const fn = FN[ sourceColorSpace ][ targetColorSpace ]; + return targetFromReference( sourceToReference( color ) ); - color.r = fn( color.r ); - color.g = fn( color.g ); - color.b = fn( color.b ); + }, - return color; + fromWorkingColorSpace: function ( color, targetColorSpace ) { - } + return this.convert( color, this._workingColorSpace, targetColorSpace ); + + }, - throw new Error( 'Unsupported color space conversion.' ); + toWorkingColorSpace: function ( color, sourceColorSpace ) { + + return this.convert( color, sourceColorSpace, this._workingColorSpace ); }, - fromWorkingColorSpace: function ( color, targetColorSpace ) { + getPrimaries: function ( colorSpace ) { - return this.convert( color, this.workingColorSpace, targetColorSpace ); + return COLOR_SPACES[ colorSpace ].primaries; }, - toWorkingColorSpace: function ( color, sourceColorSpace ) { + getTransfer: function ( colorSpace ) { - return this.convert( color, sourceColorSpace, this.workingColorSpace ); + if ( colorSpace === NoColorSpace ) return LinearTransfer; + + return COLOR_SPACES[ colorSpace ].transfer; }, }; - const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - - const _rgb$1 = { r: 0, g: 0, b: 0 }; - const _hslA = { h: 0, s: 0, l: 0 }; - const _hslB = { h: 0, s: 0, l: 0 }; - function hue2rgb( p, q, t ) { + function SRGBToLinear( c ) { - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); } - function toComponents( source, target ) { - - target.r = source.r; - target.g = source.g; - target.b = source.b; + function LinearToSRGB( c ) { - return target; + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; } - class Color { - - constructor( r, g, b ) { + let _canvas; - this.isColor = true; + class ImageUtils { - this.r = 1; - this.g = 1; - this.b = 1; + static getDataURL( image ) { - if ( g === undefined && b === undefined ) { + if ( /^data:/i.test( image.src ) ) { - // r is THREE.Color, hex or string - return this.set( r ); + return image.src; } - return this.setRGB( r, g, b ); + if ( typeof HTMLCanvasElement === 'undefined' ) { - } + return image.src; - set( value ) { + } - if ( value && value.isColor ) { + let canvas; - this.copy( value ); + if ( image instanceof HTMLCanvasElement ) { - } else if ( typeof value === 'number' ) { + canvas = image; - this.setHex( value ); + } else { - } else if ( typeof value === 'string' ) { + if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - this.setStyle( value ); + _canvas.width = image.width; + _canvas.height = image.height; - } + const context = _canvas.getContext( '2d' ); - return this; + if ( image instanceof ImageData ) { - } + context.putImageData( image, 0, 0 ); - setScalar( scalar ) { + } else { - this.r = scalar; - this.g = scalar; - this.b = scalar; + context.drawImage( image, 0, 0, image.width, image.height ); - return this; + } - } + canvas = _canvas; - setHex( hex, colorSpace = SRGBColorSpace ) { + } - hex = Math.floor( hex ); + if ( canvas.width > 2048 || canvas.height > 2048 ) { - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - ColorManagement.toWorkingColorSpace( this, colorSpace ); + return canvas.toDataURL( 'image/jpeg', 0.6 ); - return this; + } else { - } + return canvas.toDataURL( 'image/png' ); - setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { + } - this.r = r; - this.g = g; - this.b = b; + } - ColorManagement.toWorkingColorSpace( this, colorSpace ); + static sRGBToLinear( image ) { - return this; + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - } + const canvas = createElementNS( 'canvas' ); - setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { + canvas.width = image.width; + canvas.height = image.height; - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height ); - if ( s === 0 ) { + const imageData = context.getImageData( 0, 0, image.width, image.height ); + const data = imageData.data; - this.r = this.g = this.b = l; + for ( let i = 0; i < data.length; i ++ ) { - } else { + data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; + } - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); + context.putImageData( imageData, 0, 0 ); - } + return canvas; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + } else if ( image.data ) { - return this; + const data = image.data.slice( 0 ); - } + for ( let i = 0; i < data.length; i ++ ) { - setStyle( style, colorSpace = SRGBColorSpace ) { + if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - function handleAlpha( string ) { + data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - if ( string === undefined ) return; + } else { - if ( parseFloat( string ) < 1 ) { + // assuming float - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + data[ i ] = SRGBToLinear( data[ i ] ); + + } } - } + return { + data: data, + width: image.width, + height: image.height + }; + } else { - let m; + console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); + return image; - if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { + } - // rgb / hsl + } - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; + } - switch ( name ) { + let _sourceId = 0; - case 'rgb': - case 'rgba': + class Source { - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + constructor( data = null ) { - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + this.isSource = true; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + Object.defineProperty( this, 'id', { value: _sourceId ++ } ); - handleAlpha( color[ 4 ] ); + this.uuid = generateUUID(); - return this; + this.data = data; - } + this.version = 0; - 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) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + set needsUpdate( value ) { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + if ( value === true ) this.version ++; - handleAlpha( color[ 4 ] ); + } - return this; + toJSON( meta ) { - } + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - break; + if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - case 'hsl': - case 'hsla': + return meta.images[ this.uuid ]; - 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) - const h = parseFloat( color[ 1 ] ) / 360; - const s = parseFloat( color[ 2 ] ) / 100; - const l = parseFloat( color[ 3 ] ) / 100; + const output = { + uuid: this.uuid, + url: '' + }; - handleAlpha( color[ 4 ] ); + const data = this.data; - return this.setHSL( h, s, l, colorSpace ); + if ( data !== null ) { - } + let url; - break; + if ( Array.isArray( data ) ) { - } + // cube texture - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + url = []; - // hex color + for ( let i = 0, l = data.length; i < l; i ++ ) { - const hex = m[ 1 ]; - const size = hex.length; + if ( data[ i ].isDataTexture ) { - if ( size === 3 ) { + url.push( serializeImage( data[ i ].image ) ); - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + url.push( serializeImage( data[ i ] ) ); - return this; + } - } else if ( size === 6 ) { + } - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + // texture - return this; + url = serializeImage( data ); } + output.url = url; + } - if ( style && style.length > 0 ) { + if ( ! isRootObject ) { - return this.setColorName( style, colorSpace ); + meta.images[ this.uuid ] = output; } - return this; + return output; } - setColorName( style, colorSpace = SRGBColorSpace ) { + } - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; + function serializeImage( image ) { - if ( hex !== undefined ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - // red - this.setHex( hex, colorSpace ); + // default images - } else { + return ImageUtils.getDataURL( image ); - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + } else { - } + if ( image.data ) { - return this; + // images of DataTexture - } + return { + data: Array.from( image.data ), + width: image.width, + height: image.height, + type: image.data.constructor.name + }; - clone() { + } else { - return new this.constructor( this.r, this.g, this.b ); + console.warn( 'THREE.Texture: Unable to serialize Texture.' ); + return {}; + + } } - copy( color ) { + } - this.r = color.r; - this.g = color.g; - this.b = color.b; + let _textureId = 0; - return this; + class Texture extends EventDispatcher { - } + constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { - copySRGBToLinear( color ) { + super(); - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); + this.isTexture = true; - return this; + Object.defineProperty( this, 'id', { value: _textureId ++ } ); - } + this.uuid = generateUUID(); - copyLinearToSRGB( color ) { + this.name = ''; - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); + this.source = new Source( image ); + this.mipmaps = []; - return this; + this.mapping = mapping; + this.channel = 0; - } + this.wrapS = wrapS; + this.wrapT = wrapT; - convertSRGBToLinear() { + this.magFilter = magFilter; + this.minFilter = minFilter; - this.copySRGBToLinear( this ); + this.anisotropy = anisotropy; - return this; + this.format = format; + this.internalFormat = null; + this.type = type; - } + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; - convertLinearToSRGB() { + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); - this.copyLinearToSRGB( this ); + 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) - return this; + if ( typeof colorSpace === 'string' ) { - } + this.colorSpace = colorSpace; - getHex( colorSpace = SRGBColorSpace ) { + } else { // @deprecated, r152 - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - return clamp( _rgb$1.r * 255, 0, 255 ) << 16 ^ clamp( _rgb$1.g * 255, 0, 255 ) << 8 ^ clamp( _rgb$1.b * 255, 0, 255 ) << 0; + } + + + this.userData = {}; + + this.version = 0; + this.onUpdate = null; + + this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not + this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) } - getHexString( colorSpace = SRGBColorSpace ) { + get image() { - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); + return this.source.data; } - getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { + set image( value = null ) { - // h,s,l ranges are in 0.0 - 1.0 + this.source.data = value; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + } - const r = _rgb$1.r, g = _rgb$1.g, b = _rgb$1.b; + updateMatrix() { - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - let hue, saturation; - const lightness = ( min + max ) / 2.0; + } - if ( min === max ) { + clone() { - hue = 0; - saturation = 0; + return new this.constructor().copy( this ); - } else { + } - const delta = max - min; + copy( source ) { - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + this.name = source.name; - switch ( max ) { + this.source = source.source; + this.mipmaps = source.mipmaps.slice( 0 ); - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; + this.mapping = source.mapping; + this.channel = source.channel; - } + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; - hue /= 6; + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; - } + this.anisotropy = source.anisotropy; - target.h = hue; - target.s = saturation; - target.l = lightness; + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; - return target; + 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 ); - getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.colorSpace = source.colorSpace; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - target.r = _rgb$1.r; - target.g = _rgb$1.g; - target.b = _rgb$1.b; + this.needsUpdate = true; - return target; + return this; } - getStyle( colorSpace = SRGBColorSpace ) { + toJSON( meta ) { - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - if ( colorSpace !== SRGBColorSpace ) { + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ _rgb$1.r } ${ _rgb$1.g } ${ _rgb$1.b })`; + return meta.textures[ this.uuid ]; } - return `rgb(${( _rgb$1.r * 255 ) | 0},${( _rgb$1.g * 255 ) | 0},${( _rgb$1.b * 255 ) | 0})`; + const output = { - } + metadata: { + version: 4.6, + type: 'Texture', + generator: 'Texture.toJSON' + }, - offsetHSL( h, s, l ) { + uuid: this.uuid, + name: this.name, - this.getHSL( _hslA ); + image: this.source.toJSON( meta ).uuid, - _hslA.h += h; _hslA.s += s; _hslA.l += l; + mapping: this.mapping, + channel: this.channel, - this.setHSL( _hslA.h, _hslA.s, _hslA.l ); + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + center: [ this.center.x, this.center.y ], + rotation: this.rotation, - return this; + wrap: [ this.wrapS, this.wrapT ], - } + format: this.format, + internalFormat: this.internalFormat, + type: this.type, + colorSpace: this.colorSpace, - add( color ) { + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, - this.r += color.r; - this.g += color.g; - this.b += color.b; + flipY: this.flipY, - return this; + generateMipmaps: this.generateMipmaps, + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment - } + }; - addColors( color1, color2 ) { + if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + if ( ! isRootObject ) { - return this; + meta.textures[ this.uuid ] = output; - } + } - addScalar( s ) { + return output; - this.r += s; - this.g += s; - this.b += s; + } - return this; + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); } - sub( color ) { + transformUv( uv ) { - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); + if ( this.mapping !== UVMapping ) return uv; - return this; + uv.applyMatrix3( this.matrix ); - } + if ( uv.x < 0 || uv.x > 1 ) { - multiply( color ) { + switch ( this.wrapS ) { - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + case RepeatWrapping: - return this; + uv.x = uv.x - Math.floor( uv.x ); + break; - } + case ClampToEdgeWrapping: - multiplyScalar( s ) { + uv.x = uv.x < 0 ? 0 : 1; + break; - this.r *= s; - this.g *= s; - this.b *= s; + case MirroredRepeatWrapping: - return this; + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - } + uv.x = Math.ceil( uv.x ) - uv.x; - lerp( color, alpha ) { + } else { - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + uv.x = uv.x - Math.floor( uv.x ); - return this; + } - } + break; - lerpColors( color1, color2, alpha ) { + } - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; + } - return this; + if ( uv.y < 0 || uv.y > 1 ) { - } + switch ( this.wrapT ) { - lerpHSL( color, alpha ) { + case RepeatWrapping: - this.getHSL( _hslA ); - color.getHSL( _hslB ); + uv.y = uv.y - Math.floor( uv.y ); + break; - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); + case ClampToEdgeWrapping: - this.setHSL( h, s, l ); + uv.y = uv.y < 0 ? 0 : 1; + break; - return this; + case MirroredRepeatWrapping: - } + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - equals( c ) { + uv.y = Math.ceil( uv.y ) - uv.y; - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + } else { - } + uv.y = uv.y - Math.floor( uv.y ); - fromArray( array, offset = 0 ) { + } - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + break; - return this; + } - } + } - toArray( array = [], offset = 0 ) { + if ( this.flipY ) { - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; + uv.y = 1 - uv.y; - return array; + } + + return uv; } - fromBufferAttribute( attribute, index ) { + set needsUpdate( value ) { - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); + if ( value === true ) { - return this; + this.version ++; + this.source.needsUpdate = true; + + } } - toJSON() { + get encoding() { // @deprecated, r152 - return this.getHex(); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; } - *[ Symbol.iterator ]() { + set encoding( encoding ) { // @deprecated, r152 - yield this.r; - yield this.g; - yield this.b; + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; } } - Color.NAMES = _colorKeywords; + Texture.DEFAULT_IMAGE = null; + Texture.DEFAULT_MAPPING = UVMapping; + Texture.DEFAULT_ANISOTROPY = 1; - let _canvas; + class Vector4 { - class ImageUtils { + constructor( x = 0, y = 0, z = 0, w = 1 ) { - static getDataURL( image ) { + Vector4.prototype.isVector4 = true; - if ( /^data:/i.test( image.src ) ) { - - return image.src; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + } - if ( typeof HTMLCanvasElement == 'undefined' ) { + get width() { - return image.src; + return this.z; - } + } - let canvas; + set width( value ) { - if ( image instanceof HTMLCanvasElement ) { + this.z = value; - canvas = image; + } - } else { + get height() { - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); + return this.w; - _canvas.width = image.width; - _canvas.height = image.height; + } - const context = _canvas.getContext( '2d' ); + set height( value ) { - if ( image instanceof ImageData ) { + this.w = value; - context.putImageData( image, 0, 0 ); + } - } else { + set( x, y, z, w ) { - context.drawImage( image, 0, 0, image.width, image.height ); + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + return this; - canvas = _canvas; + } - } + setScalar( scalar ) { - if ( canvas.width > 2048 || canvas.height > 2048 ) { + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); + return this; - return canvas.toDataURL( 'image/jpeg', 0.6 ); + } - } else { + setX( x ) { - return canvas.toDataURL( 'image/png' ); + this.x = x; - } + return this; } - static sRGBToLinear( image ) { + setY( y ) { - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + this.y = y; - const canvas = createElementNS( 'canvas' ); + return this; - canvas.width = image.width; - canvas.height = image.height; + } - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); + setZ( z ) { - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; + this.z = z; - for ( let i = 0; i < data.length; i ++ ) { + return this; - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; + } - } + setW( w ) { - context.putImageData( imageData, 0, 0 ); + this.w = w; - return canvas; + return this; - } else if ( image.data ) { + } - const data = image.data.slice( 0 ); + setComponent( index, value ) { - for ( let i = 0; i < data.length; i ++ ) { + switch ( index ) { - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); + } - } else { + return this; - // assuming float + } - data[ i ] = SRGBToLinear( data[ i ] ); + getComponent( index ) { - } + switch ( index ) { - } + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); - return { - data: data, - width: image.width, - height: image.height - }; + } - } else { + } - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; + clone() { - } + return new this.constructor( this.x, this.y, this.z, this.w ); } - } + copy( v ) { - class Source { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - constructor( data = null ) { + return this; - this.isSource = true; + } - this.uuid = generateUUID(); + add( v ) { - this.data = data; + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - this.version = 0; + return this; } - set needsUpdate( value ) { - - if ( value === true ) this.version ++; + addScalar( s ) { - } + this.x += s; + this.y += s; + this.z += s; + this.w += s; - toJSON( meta ) { + return this; - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + } - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { + addVectors( a, b ) { - return meta.images[ this.uuid ]; + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - } + return this; - const output = { - uuid: this.uuid, - url: '' - }; + } - const data = this.data; + addScaledVector( v, s ) { - if ( data !== null ) { + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; - let url; + return this; - if ( Array.isArray( data ) ) { + } - // cube texture + sub( v ) { - url = []; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; - for ( let i = 0, l = data.length; i < l; i ++ ) { + return this; - if ( data[ i ].isDataTexture ) { + } - url.push( serializeImage( data[ i ].image ) ); + subScalar( s ) { - } else { + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - url.push( serializeImage( data[ i ] ) ); + return this; - } + } - } + subVectors( a, b ) { - } else { + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - // texture + return this; - url = serializeImage( data ); + } - } + multiply( v ) { - output.url = url; + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + this.w *= v.w; - } + return this; - if ( ! isRootObject ) { + } - meta.images[ this.uuid ] = output; + multiplyScalar( scalar ) { - } + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - return output; + return this; } - } + applyMatrix4( m ) { - function serializeImage( image ) { + const x = this.x, y = this.y, z = this.z, w = this.w; + const e = m.elements; - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + 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; - // default images + return this; - return ImageUtils.getDataURL( image ); + } - } else { - - if ( image.data ) { + divideScalar( scalar ) { - // images of DataTexture + return this.multiplyScalar( 1 / scalar ); - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; + } - } else { + setAxisAngleFromQuaternion( q ) { - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - } + // q is assumed to be normalized - } + this.w = 2 * Math.acos( q.w ); - } + const s = Math.sqrt( 1 - q.w * q.w ); - let textureId = 0; + if ( s < 0.0001 ) { - class Texture extends EventDispatcher { + this.x = 1; + this.y = 0; + this.z = 0; - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, encoding = LinearEncoding ) { + } else { - super(); + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - this.isTexture = true; + } - Object.defineProperty( this, 'id', { value: textureId ++ } ); + return this; - this.uuid = generateUUID(); + } - this.name = ''; + setAxisAngleFromRotationMatrix( m ) { - this.source = new Source( image ); - this.mipmaps = []; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - this.mapping = mapping; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - this.wrapS = wrapS; - this.wrapT = wrapT; + let angle, x, y, z; // variables for result + const epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - this.magFilter = magFilter; - this.minFilter = minFilter; + te = m.elements, - this.anisotropy = anisotropy; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - this.format = format; - this.internalFormat = null; - this.type = type; + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - 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 singularity is identity matrix so angle = 0 - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding; + this.set( 1, 0, 0, 0 ); - this.userData = {}; + return this; // zero angle, arbitrary axis - this.version = 0; - this.onUpdate = null; + } - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) + // otherwise this singularity is angle = 180 - } + angle = Math.PI; - get image() { + 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; - return this.source.data; + if ( ( xx > yy ) && ( xx > zz ) ) { - } + // m11 is the largest diagonal term - set image( value ) { + if ( xx < epsilon ) { - this.source.data = value; + x = 0; + y = 0.707106781; + z = 0.707106781; - } + } else { - updateMatrix() { + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + } - } + } else if ( yy > zz ) { - clone() { + // m22 is the largest diagonal term - return new this.constructor().copy( this ); + if ( yy < epsilon ) { - } + x = 0.707106781; + y = 0; + z = 0.707106781; - copy( source ) { + } else { - this.name = source.name; + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); + } - this.mapping = source.mapping; + } else { - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; + // m33 is the largest diagonal term so base result on this - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; + if ( zz < epsilon ) { - this.anisotropy = source.anisotropy; + x = 0.707106781; + y = 0.707106781; + z = 0; - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; + } else { - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - 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.encoding = source.encoding; + } - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + this.set( x, y, z, angle ); - this.needsUpdate = true; + return this; // return 180 deg rotation - return this; + } - } + // as we have reached here there are no singularities so we can handle normally - toJSON( meta ) { + let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + if ( Math.abs( s ) < 0.001 ) s = 1; - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case - return meta.textures[ this.uuid ]; + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - } + return this; - const output = { + } - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, + min( v ) { - uuid: this.uuid, - name: this.name, + 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 ); - image: this.source.toJSON( meta ).uuid, + return this; - mapping: this.mapping, + } - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, + max( v ) { - wrap: [ this.wrapS, this.wrapT ], + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); - format: this.format, - type: this.type, - encoding: this.encoding, + return this; - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, + } - flipY: this.flipY, + clamp( min, max ) { - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment + // assumes min < max, componentwise - }; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData; + return this; - if ( ! isRootObject ) { + } - meta.textures[ this.uuid ] = output; + clampScalar( minVal, maxVal ) { - } + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - return output; + return this; } - dispose() { + clampLength( min, max ) { - this.dispatchEvent( { type: 'dispose' } ); + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); } - transformUv( uv ) { + floor() { - if ( this.mapping !== UVMapping ) return uv; + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); - uv.applyMatrix3( this.matrix ); + return this; - if ( uv.x < 0 || uv.x > 1 ) { + } - switch ( this.wrapS ) { + ceil() { - case RepeatWrapping: + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); - uv.x = uv.x - Math.floor( uv.x ); - break; + return this; - case ClampToEdgeWrapping: + } - uv.x = uv.x < 0 ? 0 : 1; - break; + round() { - case MirroredRepeatWrapping: + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + return this; - uv.x = Math.ceil( uv.x ) - uv.x; + } - } else { + roundToZero() { - uv.x = uv.x - Math.floor( uv.x ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); + this.w = Math.trunc( this.w ); - } + return this; - break; + } - } + negate() { - } + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - if ( uv.y < 0 || uv.y > 1 ) { + return this; - switch ( this.wrapT ) { + } - case RepeatWrapping: + dot( v ) { - uv.y = uv.y - Math.floor( uv.y ); - break; + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - case ClampToEdgeWrapping: + } - uv.y = uv.y < 0 ? 0 : 1; - break; + lengthSq() { - case MirroredRepeatWrapping: + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + } - uv.y = Math.ceil( uv.y ) - uv.y; + length() { - } else { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - uv.y = uv.y - Math.floor( uv.y ); + } - } + manhattanLength() { - break; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - } + } - } + normalize() { - if ( this.flipY ) { + return this.divideScalar( this.length() || 1 ); - uv.y = 1 - uv.y; + } - } + setLength( length ) { - return uv; + return this.normalize().multiplyScalar( length ); } - set needsUpdate( value ) { - - if ( value === true ) { + lerp( v, alpha ) { - this.version ++; - this.source.needsUpdate = true; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - } + return this; } - } - - Texture.DEFAULT_IMAGE = null; - Texture.DEFAULT_MAPPING = UVMapping; - Texture.DEFAULT_ANISOTROPY = 1; - - class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { + lerpVectors( v1, v2, alpha ) { - Vector4.prototype.isVector4 = true; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + this.w = v1.w + ( v2.w - v1.w ) * alpha; - this.x = x; - this.y = y; - this.z = z; - this.w = w; + return this; } - get width() { + equals( v ) { - return this.z; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); } - set width( value ) { - - this.z = value; - - } + fromArray( array, offset = 0 ) { - get height() { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; - return this.w; + return this; } - set height( value ) { + toArray( array = [], offset = 0 ) { - this.w = value; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; } - set( x, y, z, w ) { + fromBufferAttribute( attribute, index ) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); return this; } - setScalar( scalar ) { + random() { - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); return this; } - setX( x ) { - - this.x = x; + *[ Symbol.iterator ]() { - return this; + yield this.x; + yield this.y; + yield this.z; + yield this.w; } - setY( y ) { + } - this.y = y; + /* + 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 { - return this; + constructor( width = 1, height = 1, options = {} ) { - } + super(); - setZ( z ) { + this.isRenderTarget = true; - this.z = z; + this.width = width; + this.height = height; + this.depth = 1; - return this; + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; - } + this.viewport = new Vector4( 0, 0, width, height ); - setW( w ) { + const image = { width: width, height: height, depth: 1 }; - this.w = w; + if ( options.encoding !== undefined ) { - return this; + // @deprecated, r152 + warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - } + } - setComponent( index, value ) { + options = Object.assign( { + generateMipmaps: false, + internalFormat: null, + minFilter: LinearFilter, + depthBuffer: true, + stencilBuffer: false, + depthTexture: null, + samples: 0 + }, options ); - switch ( index ) { + this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); + this.texture.isRenderTargetTexture = true; - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); + this.texture.flipY = false; + this.texture.generateMipmaps = options.generateMipmaps; + this.texture.internalFormat = options.internalFormat; - } + this.depthBuffer = options.depthBuffer; + this.stencilBuffer = options.stencilBuffer; - return this; + this.depthTexture = options.depthTexture; + + this.samples = options.samples; } - getComponent( index ) { + setSize( width, height, depth = 1 ) { - switch ( index ) { + if ( this.width !== width || this.height !== height || this.depth !== depth ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); + this.width = width; + this.height = height; + this.depth = depth; + + this.texture.image.width = width; + this.texture.image.height = height; + this.texture.image.depth = depth; + + this.dispose(); } + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + } clone() { - return new this.constructor( this.x, this.y, this.z, this.w ); + return new this.constructor().copy( this ); } - copy( v ) { + copy( source ) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + this.width = source.width; + this.height = source.height; + this.depth = source.depth; - return this; + this.scissor.copy( source.scissor ); + this.scissorTest = source.scissorTest; - } + this.viewport.copy( source.viewport ); - add( v ) { + this.texture = source.texture.clone(); + this.texture.isRenderTargetTexture = true; - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; + // ensure image object is not shared, see #20328 - return this; + const image = Object.assign( {}, source.texture.image ); + this.texture.source = new Source( image ); - } + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; - addScalar( s ) { + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - this.x += s; - this.y += s; - this.z += s; - this.w += s; + this.samples = source.samples; return this; } - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; + dispose() { - return this; + this.dispatchEvent( { type: 'dispose' } ); } - 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; + } - } + class WebGLRenderTarget extends RenderTarget { - sub( v ) { + constructor( width = 1, height = 1, options = {} ) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; + super( width, height, options ); - return this; + this.isWebGLRenderTarget = true; } - subScalar( s ) { + } - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + class DataArrayTexture extends Texture { - return this; + constructor( data = null, width = 1, height = 1, depth = 1 ) { - } + super( null ); - subVectors( a, b ) { + this.isDataArrayTexture = true; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + this.image = { data, width, height, depth }; - return this; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.wrapR = ClampToEdgeWrapping; - multiply( v ) { + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; + } - return this; + } - } + class Data3DTexture extends Texture { - multiplyScalar( scalar ) { + constructor( data = null, width = 1, height = 1, depth = 1 ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + // We're going to add .setXXX() methods for setting properties later. + // Users can still set in DataTexture3D directly. + // + // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // texture.anisotropy = 16; + // + // See #14839 - return this; + super( null ); - } + this.isData3DTexture = true; - applyMatrix4( m ) { + this.image = { data, width, height, depth }; - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - 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; + this.wrapR = ClampToEdgeWrapping; - return this; + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; } - divideScalar( scalar ) { + } - return this.multiplyScalar( 1 / scalar ); + class Quaternion { - } + constructor( x = 0, y = 0, z = 0, w = 1 ) { - setAxisAngleFromQuaternion( q ) { + this.isQuaternion = true; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + this._x = x; + this._y = y; + this._z = z; + this._w = w; - // q is assumed to be normalized + } - this.w = 2 * Math.acos( q.w ); + static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - const s = Math.sqrt( 1 - q.w * q.w ); + // fuzz-free, array-based Quaternion SLERP operation - if ( s < 0.0001 ) { + let x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; - this.x = 1; - this.y = 0; - this.z = 0; + const x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; - } else { + if ( t === 0 ) { - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + dst[ dstOffset + 0 ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + return; } - return this; + if ( t === 1 ) { - } + dst[ dstOffset + 0 ] = x1; + dst[ dstOffset + 1 ] = y1; + dst[ dstOffset + 2 ] = z1; + dst[ dstOffset + 3 ] = w1; + return; - setAxisAngleFromRotationMatrix( m ) { + } - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + let s = 1 - t; + const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { - te = m.elements, + const sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { + } - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + const tDir = t * dir; - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; - // this singularity is identity matrix so angle = 0 + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { - this.set( 1, 0, 0, 0 ); + const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - return this; // zero angle, arbitrary axis + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; } - // otherwise this singularity is angle = 180 + } - angle = Math.PI; + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; - 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 > yy ) && ( xx > zz ) ) { + static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - // m11 is the largest diagonal term + const x0 = src0[ srcOffset0 ]; + const y0 = src0[ srcOffset0 + 1 ]; + const z0 = src0[ srcOffset0 + 2 ]; + const w0 = src0[ srcOffset0 + 3 ]; - if ( xx < epsilon ) { + const x1 = src1[ srcOffset1 ]; + const y1 = src1[ srcOffset1 + 1 ]; + const z1 = src1[ srcOffset1 + 2 ]; + const w1 = src1[ srcOffset1 + 3 ]; - x = 0; - y = 0.707106781; - z = 0.707106781; + dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; + dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; + dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; + dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - } else { + return dst; - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; + } - } + get x() { - } else if ( yy > zz ) { + return this._x; - // m22 is the largest diagonal term + } - if ( yy < epsilon ) { + set x( value ) { - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + this._x = value; + this._onChangeCallback(); - } + } - } else { + get y() { - // m33 is the largest diagonal term so base result on this + return this._y; - if ( zz < epsilon ) { + } - x = 0.707106781; - y = 0.707106781; - z = 0; + set y( value ) { - } else { + this._y = value; + this._onChangeCallback(); - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + } - } + get z() { - } + return this._z; - this.set( x, y, z, angle ); + } - return this; // return 180 deg rotation + set z( value ) { - } + this._z = value; + this._onChangeCallback(); - // as we have reached here there are no singularities so we can handle normally + } - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + get w() { - if ( Math.abs( s ) < 0.001 ) s = 1; + return this._w; - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case + } - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + set w( value ) { - return this; + this._w = value; + this._onChangeCallback(); } - min( v ) { + set( x, y, z, w ) { - 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 ); + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._onChangeCallback(); return this; } - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); + clone() { - return this; + return new this.constructor( this._x, this._y, this._z, this._w ); } - clamp( min, max ) { + copy( quaternion ) { - // assumes min < max, componentwise + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + this._onChangeCallback(); return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; + setFromEuler( euler, update = true ) { - } + const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - clampLength( min, max ) { + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - const length = this.length(); + const cos = Math.cos; + const sin = Math.sin; - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + 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 ); - floor() { + switch ( order ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); + 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; - return this; + 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; - ceil() { + 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; - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); + 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; - return this; + 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 ); - round() { + } - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); + if ( update === true ) this._onChangeCallback(); return this; } - roundToZero() { + setFromAxisAngle( axis, angle ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - return this; + // assumes axis is normalized - } + const halfAngle = angle / 2, s = Math.sin( halfAngle ); - negate() { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; + this._onChangeCallback(); return this; } - dot( v ) { + setFromRotationMatrix( m ) { - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - } + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - lengthSq() { + const te = m.elements, - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - } + trace = m11 + m22 + m33; - length() { + if ( trace > 0 ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + const s = 0.5 / Math.sqrt( trace + 1.0 ); - } + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - manhattanLength() { + } else if ( m11 > m22 && m11 > m33 ) { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - } + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - normalize() { + } else if ( m22 > m33 ) { - return this.divideScalar( this.length() || 1 ); + const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - } + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - setLength( length ) { + } else { - return this.normalize().multiplyScalar( length ); + const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - } + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - lerp( v, alpha ) { + } - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; + this._onChangeCallback(); return this; } - lerpVectors( v1, v2, alpha ) { + setFromUnitVectors( vFrom, vTo ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } + // assumes direction vectors vFrom and vTo are normalized - equals( v ) { + let r = vFrom.dot( vTo ) + 1; - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + if ( r < Number.EPSILON ) { - } + // vFrom and vTo point in opposite directions - fromArray( array, offset = 0 ) { + r = 0; - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - return this; + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; - } + } else { - toArray( array = [], offset = 0 ) { + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; + } - return array; + } else { - } + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - fromBufferAttribute( attribute, index ) { + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); + } - return this; + return this.normalize(); } - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); + angleTo( q ) { - return this; + return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); } - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - yield this.w; + rotateTowards( q, step ) { - } + const angle = this.angleTo( q ); - } + if ( angle === 0 ) return this; - /* - 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 WebGLRenderTarget extends EventDispatcher { + const t = Math.min( 1, step / angle ); - constructor( width = 1, height = 1, options = {} ) { + this.slerp( q, t ); - super(); + return this; - this.isWebGLRenderTarget = true; + } - this.width = width; - this.height = height; - this.depth = 1; + identity() { - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; + return this.set( 0, 0, 0, 1 ); - this.viewport = new Vector4( 0, 0, width, height ); + } - const image = { width: width, height: height, depth: 1 }; + invert() { - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; + // quaternion is assumed to have unit length - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + return this.conjugate(); - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; + } - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + conjugate() { - this.samples = options.samples !== undefined ? options.samples : 0; + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - } + this._onChangeCallback(); - setSize( width, height, depth = 1 ) { + return this; - if ( this.width !== width || this.height !== height || this.depth !== depth ) { + } - this.width = width; - this.height = height; - this.depth = depth; + dot( v ) { - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - this.dispose(); + } - } + lengthSq() { - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } - clone() { + length() { - return new this.constructor().copy( this ); + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); } - copy( source ) { + normalize() { - this.width = source.width; - this.height = source.height; - this.depth = source.depth; + let l = this.length(); - this.viewport.copy( source.viewport ); + if ( l === 0 ) { - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - // ensure image object is not shared, see #20328 + } else { - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); + l = 1 / l; - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + } - this.samples = source.samples; + this._onChangeCallback(); return this; } - dispose() { + multiply( q ) { - this.dispatchEvent( { type: 'dispose' } ); + return this.multiplyQuaternions( this, q ); } - } + premultiply( q ) { - class DataArrayTexture extends Texture { + return this.multiplyQuaternions( q, this ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + } - super( null ); + multiplyQuaternions( a, b ) { - this.isDataArrayTexture = true; + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - this.image = { data, width, height, depth }; + const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - this.wrapR = ClampToEdgeWrapping; + this._onChangeCallback(); - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + return this; } - } + slerp( qb, t ) { - class Data3DTexture extends Texture { + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + const x = this._x, y = this._y, z = this._z, w = this._w; - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - super( null ); + let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - this.isData3DTexture = true; + if ( cosHalfTheta < 0 ) { - this.image = { data, width, height, depth }; + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + cosHalfTheta = - cosHalfTheta; - this.wrapR = ClampToEdgeWrapping; + } else { - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + this.copy( qb ); - } + } - } + if ( cosHalfTheta >= 1.0 ) { - class Quaternion { + this._w = w; + this._x = x; + this._y = y; + this._z = z; - constructor( x = 0, y = 0, z = 0, w = 1 ) { + return this; - this.isQuaternion = true; + } - this._x = x; - this._y = y; - this._z = z; - this._w = w; + const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - } + if ( sqrSinHalfTheta <= Number.EPSILON ) { - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + 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; - // fuzz-free, array-based Quaternion SLERP operation + this.normalize(); // normalize calls _onChangeCallback() - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; + return this; } - if ( t === 1 ) { + const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - } + this._onChangeCallback(); - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + return this; - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; + } - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { + slerpQuaternions( qa, qb, t ) { - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); + return this.copy( qa ).slerp( qb, t ); - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; + } - } + random() { - const tDir = t * dir; + // Derived from http://planning.cs.uiuc.edu/node198.html + // Note, this source uses w, x, y, z ordering, + // so we swap the order below. - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; + const u1 = Math.random(); + const sqrt1u1 = Math.sqrt( 1 - u1 ); + const sqrtu1 = Math.sqrt( u1 ); - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { + const u2 = 2 * Math.PI * Math.random(); - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + const u3 = 2 * Math.PI * Math.random(); - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; + return this.set( + sqrt1u1 * Math.cos( u2 ), + sqrtu1 * Math.sin( u3 ), + sqrtu1 * Math.cos( u3 ), + sqrt1u1 * Math.sin( u2 ), + ); - } + } - } + equals( quaternion ) { - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); } - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; + fromArray( array, offset = 0 ) { - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; + this._onChangeCallback(); - return dst; + return this; } - get x() { + toArray( array = [], offset = 0 ) { - return this._x; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - } + return array; - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + fromBufferAttribute( attribute, index ) { - } + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); - get y() { + this._onChangeCallback(); - return this._y; + return this; } - set y( value ) { + toJSON() { - this._y = value; - this._onChangeCallback(); + return this.toArray(); } - get z() { + _onChange( callback ) { - return this._z; + this._onChangeCallback = callback; + + return this; } - set z( value ) { + _onChangeCallback() {} - this._z = value; - this._onChangeCallback(); + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._w; } - get w() { + } - return this._w; + class Vector3 { - } + constructor( x = 0, y = 0, z = 0 ) { - set w( value ) { + Vector3.prototype.isVector3 = true; - this._w = value; - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; } - set( x, y, z, w ) { + set( x, y, z ) { - this._x = x; - this._y = y; - this._z = z; - this._w = w; + if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; return this; } - clone() { + setScalar( scalar ) { - return new this.constructor( this._x, this._y, this._z, this._w ); + this.x = scalar; + this.y = scalar; + this.z = scalar; - } + return this; - copy( quaternion ) { + } - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + setX( x ) { - this._onChangeCallback(); + this.x = x; return this; } - setFromEuler( euler, update ) { - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; + setY( y ) { - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); + this.y = y; - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); + return this; - 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; + setZ( z ) { - 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; + this.z = z; - 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; + return this; - 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; + setComponent( index, value ) { - 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; + switch ( index ) { - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - if ( update !== false ) this._onChangeCallback(); - return this; } - setFromAxisAngle( axis, angle ) { + getComponent( index ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + switch ( index ) { - // assumes axis is normalized + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); - const halfAngle = angle / 2, s = Math.sin( halfAngle ); + } - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + } - this._onChangeCallback(); + clone() { - return this; + return new this.constructor( this.x, this.y, this.z ); } - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + copy( v ) { - const te = m.elements, + this.x = v.x; + this.y = v.y; + this.z = v.z; - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + return this; - trace = m11 + m22 + m33; + } - if ( trace > 0 ) { + add( v ) { - const s = 0.5 / Math.sqrt( trace + 1.0 ); + this.x += v.x; + this.y += v.y; + this.z += v.z; - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + return this; - } else if ( m11 > m22 && m11 > m33 ) { + } - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + addScalar( s ) { - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + this.x += s; + this.y += s; + this.z += s; - } else if ( m22 > m33 ) { + return this; - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + } - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + addVectors( a, b ) { - } else { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + return this; - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + } - } + addScaledVector( v, s ) { - this._onChangeCallback(); + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; return this; } - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized + sub( v ) { - let r = vFrom.dot( vTo ) + 1; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - if ( r < Number.EPSILON ) { + return this; - // vFrom and vTo point in opposite directions + } - r = 0; + subScalar( s ) { - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + this.x -= s; + this.y -= s; + this.z -= s; - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; + return this; - } else { + } - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; + subVectors( a, b ) { - } + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - } else { + return this; - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + } - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; + multiply( v ) { - } + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; - return this.normalize(); + return this; } - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } + multiplyScalar( scalar ) { - rotateTowards( q, step ) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - const angle = this.angleTo( q ); + return this; - if ( angle === 0 ) return this; + } - const t = Math.min( 1, step / angle ); + multiplyVectors( a, b ) { - this.slerp( q, t ); + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; return this; } - identity() { + applyEuler( euler ) { - return this.set( 0, 0, 0, 1 ); + return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); } - invert() { - - // quaternion is assumed to have unit length + applyAxisAngle( axis, angle ) { - return this.conjugate(); + return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); } - conjugate() { + applyMatrix3( m ) { - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - this._onChangeCallback(); + 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; } - dot( v ) { + applyNormalMatrix( m ) { - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + return this.applyMatrix3( m ).normalize(); } - lengthSq() { + applyMatrix4( m ) { - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - } + const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - length() { + 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 Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + return this; } - normalize() { - - let l = this.length(); + applyQuaternion( q ) { - if ( l === 0 ) { + // quaternion q is assumed to have unit length - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + const vx = this.x, vy = this.y, vz = this.z; + const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - } else { + // 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 ); - l = 1 / l; + // v + q.w * t + cross( q.xyz, t ); + this.x = vx + qw * tx + qy * tz - qz * ty; + this.y = vy + qw * ty + qz * tx - qx * tz; + this.z = vz + qw * tz + qx * ty - qy * tx; - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + return this; - } + } - this._onChangeCallback(); + project( camera ) { - return this; + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); } - multiply( q ) { + unproject( camera ) { - return this.multiplyQuaternions( this, q ); + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); } - premultiply( q ) { + transformDirection( m ) { - return this.multiplyQuaternions( q, this ); + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - } + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - multiplyQuaternions( a, b ) { + 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; - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + return this.normalize(); - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + } - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + divide( v ) { - this._onChangeCallback(); + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; return this; } - slerp( qb, t ) { + divideScalar( scalar ) { - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); + return this.multiplyScalar( 1 / scalar ); - const x = this._x, y = this._y, z = this._z, w = this._w; + } - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + min( v ) { - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { + return this; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + } - return this; + max( v ) { - } + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + return this; - if ( sqrSinHalfTheta <= Number.EPSILON ) { + } - 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; + clamp( min, max ) { - this.normalize(); - this._onChangeCallback(); + // assumes min < max, componentwise - return this; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - } + return this; - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + } - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); + clampScalar( minVal, maxVal ) { - this._onChangeCallback(); + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); return this; } - slerpQuaternions( qa, qb, t ) { - - return this.copy( qa ).slerp( qb, t ); - - } + clampLength( min, max ) { - random() { + const length = this.length(); - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); + } - const u2 = 2 * Math.PI * Math.random(); + floor() { - const u3 = 2 * Math.PI * Math.random(); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); + return this; } - equals( quaternion ) { + ceil() { - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - } + return this; - fromArray( array, offset = 0 ) { + } - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; + round() { - this._onChangeCallback(); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); return this; } - toArray( array = [], offset = 0 ) { + roundToZero() { - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); - return array; + return this; } - fromBufferAttribute( attribute, index ) { + negate() { - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; return this; } - _onChange( callback ) { - - this._onChangeCallback = callback; + dot( v ) { - return this; + return this.x * v.x + this.y * v.y + this.z * v.z; } - _onChangeCallback() {} + // TODO lengthSquared? - *[ Symbol.iterator ]() { + lengthSq() { - yield this._x; - yield this._y; - yield this._z; - yield this._w; + return this.x * this.x + this.y * this.y + this.z * this.z; } - } + length() { - class Vector3 { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - constructor( x = 0, y = 0, z = 0 ) { + } - Vector3.prototype.isVector3 = true; + manhattanLength() { - this.x = x; - this.y = y; - this.z = z; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); } - set( x, y, z ) { + normalize() { - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) + return this.divideScalar( this.length() || 1 ); - this.x = x; - this.y = y; - this.z = z; + } - return this; + setLength( length ) { + + return this.normalize().multiplyScalar( length ); } - setScalar( scalar ) { + lerp( v, alpha ) { - this.x = scalar; - this.y = scalar; - this.z = scalar; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; return this; } - setX( x ) { + lerpVectors( v1, v2, alpha ) { - this.x = x; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; return this; } - setY( y ) { - - this.y = y; + cross( v ) { - return this; + return this.crossVectors( this, v ); } - setZ( z ) { + crossVectors( a, b ) { - this.z = z; + 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; } - setComponent( index, value ) { + projectOnVector( v ) { - switch ( index ) { + const denominator = v.lengthSq(); - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); + if ( denominator === 0 ) return this.set( 0, 0, 0 ); - } + const scalar = v.dot( this ) / denominator; - return this; + return this.copy( v ).multiplyScalar( scalar ); } - getComponent( index ) { - - switch ( index ) { + projectOnPlane( planeNormal ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); + _vector$c.copy( this ).projectOnVector( planeNormal ); - } + return this.sub( _vector$c ); } - clone() { + reflect( normal ) { - return new this.constructor( this.x, this.y, this.z ); + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - } + return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - copy( v ) { + } - this.x = v.x; - this.y = v.y; - this.z = v.z; + angleTo( v ) { - return this; + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - } + if ( denominator === 0 ) return Math.PI / 2; - add( v ) { + const theta = this.dot( v ) / denominator; - this.x += v.x; - this.y += v.y; - this.z += v.z; + // clamp, to handle numerical problems - return this; + return Math.acos( clamp( theta, - 1, 1 ) ); } - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; + distanceTo( v ) { - return this; + return Math.sqrt( this.distanceToSquared( v ) ); } - addVectors( a, b ) { + distanceToSquared( v ) { - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return this; + return dx * dx + dy * dy + dz * dz; } - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; + manhattanDistanceTo( v ) { - return this; + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); } - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + setFromSpherical( s ) { - return this; + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); } - subScalar( s ) { + setFromSphericalCoords( radius, phi, theta ) { - this.x -= s; - this.y -= s; - this.z -= s; + const sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); return this; } - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + setFromCylindrical( c ) { - return this; + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); } - multiply( v ) { + setFromCylindricalCoords( radius, theta, y ) { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); return this; } - multiplyScalar( scalar ) { + setFromMatrixPosition( m ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; return this; } - multiplyVectors( a, b ) { + setFromMatrixScale( m ) { - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + const sx = this.setFromMatrixColumn( m, 0 ).length(); + const sy = this.setFromMatrixColumn( m, 1 ).length(); + const sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; return this; } - applyEuler( euler ) { + setFromMatrixColumn( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); + return this.fromArray( m.elements, index * 4 ); } - applyAxisAngle( axis, angle ) { + setFromMatrix3Column( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); + return this.fromArray( m.elements, index * 3 ); } - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + setFromEuler( e ) { - 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; + this.x = e._x; + this.y = e._y; + this.z = e._z; return this; } - applyNormalMatrix( m ) { + setFromColor( c ) { - return this.applyMatrix3( m ).normalize(); + this.x = c.r; + this.y = c.g; + this.z = c.b; + + return this; } - applyMatrix4( m ) { + equals( v ) { - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - 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; + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; return this; } - applyQuaternion( q ) { + toArray( array = [], offset = 0 ) { - const x = this.x, y = this.y, z = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - // calculate quat * vector + return array; - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = - qx * x - qy * y - qz * z; + } - // calculate result * inverse quat + fromBufferAttribute( attribute, index ) { - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); return this; } - project( camera ) { + random() { - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + + return this; } - unproject( camera ) { + randomDirection() { - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); + // Derived from https://mathworld.wolfram.com/SpherePointPicking.html - } + const u = ( Math.random() - 0.5 ) * 2; + const t = Math.random() * Math.PI * 2; + const f = Math.sqrt( 1 - u ** 2 ); - transformDirection( m ) { + this.x = f * Math.cos( t ); + this.y = f * Math.sin( t ); + this.z = u; - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + return this; - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + } - 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; + *[ Symbol.iterator ]() { - return this.normalize(); + yield this.x; + yield this.y; + yield this.z; } - divide( v ) { + } - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + const _vector$c = /*@__PURE__*/ new Vector3(); + const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - return this; + class Box3 { - } + constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - divideScalar( scalar ) { + this.isBox3 = true; - return this.multiplyScalar( 1 / scalar ); + this.min = min; + this.max = max; } - min( v ) { + set( min, max ) { - 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.min.copy( min ); + this.max.copy( max ); return this; } - max( v ) { + setFromArray( array ) { - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); + this.makeEmpty(); + + for ( let i = 0, il = array.length; i < il; i += 3 ) { + + this.expandByPoint( _vector$b.fromArray( array, i ) ); + + } return this; } - clamp( min, max ) { + setFromBufferAttribute( attribute ) { - // assumes min < max, componentwise + this.makeEmpty(); - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + for ( let i = 0, il = attribute.count; i < il; i ++ ) { + + this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); + + } return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + setFromPoints( points ) { - return this; + this.makeEmpty(); - } + for ( let i = 0, il = points.length; i < il; i ++ ) { - clampLength( min, max ) { + this.expandByPoint( points[ i ] ); - const length = this.length(); + } - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + return this; } - floor() { + setFromCenterAndSize( center, size ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); + const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); return this; } - ceil() { + setFromObject( object, precise = false ) { - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); + this.makeEmpty(); - return this; + return this.expandByObject( object, precise ); } - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); + clone() { - return this; + return new this.constructor().copy( this ); } - roundToZero() { + copy( box ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.min.copy( box.min ); + this.max.copy( box.max ); return this; } - negate() { + makeEmpty() { - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; return this; } - dot( v ) { + isEmpty() { - return this.x * v.x + this.y * v.y + this.z * v.z; + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - } + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - // TODO lengthSquared? + } - lengthSq() { + getCenter( target ) { - return this.x * this.x + this.y * this.y + this.z * this.z; + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); } - length() { + getSize( target ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); } - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } + expandByPoint( point ) { - normalize() { + this.min.min( point ); + this.max.max( point ); - return this.divideScalar( this.length() || 1 ); + return this; } - setLength( length ) { + expandByVector( vector ) { - return this.normalize().multiplyScalar( length ); + this.min.sub( vector ); + this.max.add( vector ); + + return this; } - lerp( v, alpha ) { + expandByScalar( scalar ) { - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); return this; } - lerpVectors( v1, v2, alpha ) { + expandByObject( object, precise = false ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - return this; + object.updateWorldMatrix( false, false ); - } + const geometry = object.geometry; - cross( v ) { + if ( geometry !== undefined ) { - return this.crossVectors( this, v ); + const positionAttribute = geometry.getAttribute( 'position' ); - } + // precise AABB computation based on vertex data requires at least a position attribute. + // instancing isn't supported so far and uses the normal (conservative) code path. - crossVectors( a, b ) { + if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; + for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + if ( object.isMesh === true ) { - return this; + object.getVertexPosition( i, _vector$b ); - } + } else { - projectOnVector( v ) { + _vector$b.fromBufferAttribute( positionAttribute, i ); - const denominator = v.lengthSq(); + } - if ( denominator === 0 ) return this.set( 0, 0, 0 ); + _vector$b.applyMatrix4( object.matrixWorld ); + this.expandByPoint( _vector$b ); - const scalar = v.dot( this ) / denominator; + } - return this.copy( v ).multiplyScalar( scalar ); + } else { - } + if ( object.boundingBox !== undefined ) { - projectOnPlane( planeNormal ) { + // object-level bounding box - _vector$c.copy( this ).projectOnVector( planeNormal ); + if ( object.boundingBox === null ) { - return this.sub( _vector$c ); + object.computeBoundingBox(); - } + } - reflect( normal ) { + _box$4.copy( object.boundingBox ); - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + } else { - } + // geometry-level bounding box - angleTo( v ) { + if ( geometry.boundingBox === null ) { - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + geometry.computeBoundingBox(); - if ( denominator === 0 ) return Math.PI / 2; + } - const theta = this.dot( v ) / denominator; + _box$4.copy( geometry.boundingBox ); - // clamp, to handle numerical problems + } - return Math.acos( clamp( theta, - 1, 1 ) ); + _box$4.applyMatrix4( object.matrixWorld ); - } + this.union( _box$4 ); - distanceTo( v ) { + } - return Math.sqrt( this.distanceToSquared( v ) ); + } - } + const children = object.children; - distanceToSquared( v ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + this.expandByObject( children[ i ], precise ); - return dx * dx + dy * dy + dz * dz; + } + + return this; } - manhattanDistanceTo( v ) { + containsPoint( point ) { - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ? false : true; } - setFromSpherical( s ) { + containsBox( box ) { - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; } - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; + getParameter( point, target ) { - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - return this; + 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 ) + ); } - setFromCylindrical( c ) { + intersectsBox( box ) { - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; } - setFromCylindricalCoords( radius, theta, y ) { + intersectsSphere( sphere ) { - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$b ); - return this; + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); } - setFromMatrixPosition( m ) { + intersectsPlane( plane ) { - const e = m.elements; + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; + let min, max; - return this; + if ( plane.normal.x > 0 ) { - } + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; - setFromMatrixScale( m ) { + } else { - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - this.x = sx; - this.y = sy; - this.z = sz; + } - return this; + if ( plane.normal.y > 0 ) { - } + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - setFromMatrixColumn( m, index ) { + } else { - return this.fromArray( m.elements, index * 4 ); + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; - } + } - setFromMatrix3Column( m, index ) { + if ( plane.normal.z > 0 ) { - return this.fromArray( m.elements, index * 3 ); + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; - } + } else { - setFromEuler( e ) { + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; - this.x = e._x; - this.y = e._y; - this.z = e._z; + } - return this; + return ( min <= - plane.constant && max >= - plane.constant ); } - equals( v ) { + intersectsTriangle( triangle ) { - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + if ( this.isEmpty() ) { - } + return false; - fromArray( array, offset = 0 ) { + } - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); - return this; + // translate triangle to aabb origin + _v0$2.subVectors( triangle.a, _center ); + _v1$7.subVectors( triangle.b, _center ); + _v2$4.subVectors( triangle.c, _center ); - } + // compute edge vectors for triangle + _f0.subVectors( _v1$7, _v0$2 ); + _f1.subVectors( _v2$4, _v1$7 ); + _f2.subVectors( _v0$2, _v2$4 ); - toArray( array = [], offset = 0 ) { + // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb + // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation + // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) + let axes = [ + 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, + _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, + - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 + ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; + return false; - return array; + } - } + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - fromBufferAttribute( attribute, index ) { + return false; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); + } - return this; + // finally testing the face normal of the triangle + // use already existing triangle edge vectors here + _triangleNormal.crossVectors( _f0, _f1 ); + axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + + return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); } - random() { + clampPoint( point, target ) { - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); + return target.copy( point ).clamp( this.min, this.max ); - return this; + } + + distanceToPoint( point ) { + + return this.clampPoint( point, _vector$b ).distanceTo( point ); } - randomDirection() { + getBoundingSphere( target ) { - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html + if ( this.isEmpty() ) { - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); + target.makeEmpty(); - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; + } else { - return this; + this.getCenter( target.center ); - } + target.radius = this.getSize( _vector$b ).length() * 0.5; - *[ Symbol.iterator ]() { + } - yield this.x; - yield this.y; - yield this.z; + return target; } - } + intersect( box ) { - const _vector$c = /*@__PURE__*/ new Vector3(); - const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + this.min.max( box.min ); + this.max.min( box.max ); - class Box3 { + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + return this; - this.isBox3 = true; + } - this.min = min; - this.max = max; + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; } - set( min, max ) { + applyMatrix4( matrix ) { - this.min.copy( min ); - this.max.copy( max ); + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.setFromPoints( _points ); return this; } - setFromArray( array ) { + translate( offset ) { - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + this.min.add( offset ); + this.max.add( offset ); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + return this; - for ( let i = 0, l = array.length; i < l; i += 3 ) { + } - const x = array[ i ]; - const y = array[ i + 1 ]; - const z = array[ i + 2 ]; + equals( box ) { - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + return box.min.equals( this.min ) && box.max.equals( this.max ); - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + } - } + } - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + 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() + ]; - return this; + const _vector$b = /*@__PURE__*/ new Vector3(); - } + const _box$4 = /*@__PURE__*/ new Box3(); - setFromBufferAttribute( attribute ) { + // triangle centered vertices - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + const _v0$2 = /*@__PURE__*/ new Vector3(); + const _v1$7 = /*@__PURE__*/ new Vector3(); + const _v2$4 = /*@__PURE__*/ new Vector3(); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + // triangle edge vectors - for ( let i = 0, l = attribute.count; i < l; i ++ ) { + const _f0 = /*@__PURE__*/ new Vector3(); + const _f1 = /*@__PURE__*/ new Vector3(); + const _f2 = /*@__PURE__*/ new Vector3(); - const x = attribute.getX( i ); - const y = attribute.getY( i ); - const z = attribute.getZ( i ); + const _center = /*@__PURE__*/ new Vector3(); + const _extents = /*@__PURE__*/ new Vector3(); + const _triangleNormal = /*@__PURE__*/ new Vector3(); + const _testAxis = /*@__PURE__*/ new Vector3(); - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + function satForAxes( axes, v0, v1, v2, extents ) { - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - } + _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 ) { - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is separating and we can exit + return false; - return this; + } } - setFromPoints( points ) { + return true; - this.makeEmpty(); + } - for ( let i = 0, il = points.length; i < il; i ++ ) { + const _box$3 = /*@__PURE__*/ new Box3(); + const _v1$6 = /*@__PURE__*/ new Vector3(); + const _v2$3 = /*@__PURE__*/ new Vector3(); - this.expandByPoint( points[ i ] ); + class Sphere { - } + constructor( center = new Vector3(), radius = - 1 ) { - return this; + this.isSphere = true; - } + this.center = center; + this.radius = radius; - setFromCenterAndSize( center, size ) { + } - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + set( center, radius ) { - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + this.center.copy( center ); + this.radius = radius; return this; } - setFromObject( object, precise = false ) { + setFromPoints( points, optionalCenter ) { - this.makeEmpty(); + const center = this.center; - return this.expandByObject( object, precise ); + if ( optionalCenter !== undefined ) { - } + center.copy( optionalCenter ); - clone() { + } else { - return new this.constructor().copy( this ); + _box$3.setFromPoints( points ).getCenter( center ); - } + } - copy( box ) { + let maxRadiusSq = 0; - this.min.copy( box.min ); - this.max.copy( box.max ); + for ( let i = 0, il = points.length; i < il; i ++ ) { + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); return this; } - makeEmpty() { + copy( sphere ) { - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + this.center.copy( sphere.center ); + this.radius = sphere.radius; return this; @@ -4733,1205 +5029,1271 @@ isEmpty() { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + return ( this.radius < 0 ); } - getCenter( target ) { + makeEmpty() { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; } - getSize( target ) { + containsPoint( point ) { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); } - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); + distanceToPoint( point ) { - return this; + return ( point.distanceTo( this.center ) - this.radius ); } - expandByVector( vector ) { + intersectsSphere( sphere ) { - this.min.sub( vector ); - this.max.add( vector ); + const radiusSum = this.radius + sphere.radius; - return this; + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); } - expandByScalar( scalar ) { + intersectsBox( box ) { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + return box.intersectsSphere( this ); - return this; + } + + intersectsPlane( plane ) { + + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; } - expandByObject( object, precise = false ) { + clampPoint( point, target ) { - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + const deltaLengthSq = this.center.distanceToSquared( point ); - object.updateWorldMatrix( false, false ); + target.copy( point ); - const geometry = object.geometry; + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - if ( geometry !== undefined ) { + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); - if ( precise && geometry.attributes != undefined && geometry.attributes.position !== undefined ) { + } - const position = geometry.attributes.position; - for ( let i = 0, l = position.count; i < l; i ++ ) { + return target; - _vector$b.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); + } - } + getBoundingBox( target ) { - } else { + if ( this.isEmpty() ) { - if ( geometry.boundingBox === null ) { + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; - geometry.computeBoundingBox(); + } - } + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); - _box$3.copy( geometry.boundingBox ); - _box$3.applyMatrix4( object.matrixWorld ); + return target; - this.union( _box$3 ); + } - } + applyMatrix4( matrix ) { - } + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - const children = object.children; + return this; - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - this.expandByObject( children[ i ], precise ); + translate( offset ) { - } + this.center.add( offset ); return this; } - containsPoint( point ) { + expandByPoint( point ) { - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; + if ( this.isEmpty() ) { - } + this.center.copy( point ); - containsBox( box ) { + this.radius = 0; - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; + return this; - } + } - getParameter( point, target ) { + _v1$6.subVectors( point, this.center ); - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + const lengthSq = _v1$6.lengthSq(); - 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 ) - ); + if ( lengthSq > ( this.radius * this.radius ) ) { - } + // calculate the minimal sphere - intersectsBox( box ) { + const length = Math.sqrt( lengthSq ); - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + const delta = ( length - this.radius ) * 0.5; - } + this.center.addScaledVector( _v1$6, delta / length ); - intersectsSphere( sphere ) { + this.radius += delta; - // 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 ); + return this; } - intersectsPlane( plane ) { + union( sphere ) { - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. + if ( sphere.isEmpty() ) { - let min, max; + return this; - if ( plane.normal.x > 0 ) { + } - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; + if ( this.isEmpty() ) { - } else { + this.copy( sphere ); - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + return this; } - if ( plane.normal.y > 0 ) { + if ( this.center.equals( sphere.center ) === true ) { - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; + this.radius = Math.max( this.radius, sphere.radius ); } else { - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); - } else { + this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); } - return ( min <= - plane.constant && max >= - plane.constant ); + return this; } - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } + equals( sphere ) { - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$4.subVectors( triangle.c, _center ); + } - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$4, _v1$7 ); - _f2.subVectors( _v0$2, _v2$4 ); + clone() { - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + return new this.constructor().copy( this ); - return false; + } - } + } - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + const _vector$a = /*@__PURE__*/ new Vector3(); + const _segCenter = /*@__PURE__*/ new Vector3(); + const _segDir = /*@__PURE__*/ new Vector3(); + const _diff = /*@__PURE__*/ new Vector3(); - return false; + const _edge1 = /*@__PURE__*/ new Vector3(); + const _edge2 = /*@__PURE__*/ new Vector3(); + const _normal$1 = /*@__PURE__*/ new Vector3(); - } + class Ray { - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); + this.origin = origin; + this.direction = direction; } - clampPoint( point, target ) { + set( origin, direction ) { - return target.copy( point ).clamp( this.min, this.max ); + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; } - distanceToPoint( point ) { + copy( ray ) { - const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); - return clampedPoint.sub( point ).length(); + return this; } - getBoundingSphere( target ) { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; + at( t, target ) { - return target; + return target.copy( this.origin ).addScaledVector( this.direction, t ); } - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); + lookAt( v ) { - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); + this.direction.copy( v ).sub( this.origin ).normalize(); return this; } - union( box ) { + recast( t ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.origin.copy( this.at( t, _vector$a ) ); return this; } - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + closestPointToPoint( point, target ) { - this.setFromPoints( _points ); + target.subVectors( point, this.origin ); - return this; + const directionDistance = target.dot( this.direction ); - } + if ( directionDistance < 0 ) { - translate( offset ) { + return target.copy( this.origin ); - this.min.add( offset ); - this.max.add( offset ); + } - return this; + return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); } - equals( box ) { + distanceToPoint( point ) { - return box.min.equals( this.min ) && box.max.equals( this.max ); + return Math.sqrt( this.distanceSqToPoint( point ) ); } - } + distanceSqToPoint( point ) { - 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() - ]; + const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - const _vector$b = /*@__PURE__*/ new Vector3(); + // point behind the ray - const _box$3 = /*@__PURE__*/ new Box3(); + if ( directionDistance < 0 ) { - // triangle centered vertices + return this.origin.distanceToSquared( point ); - const _v0$2 = /*@__PURE__*/ new Vector3(); - const _v1$7 = /*@__PURE__*/ new Vector3(); - const _v2$4 = /*@__PURE__*/ new Vector3(); + } - // triangle edge vectors + _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - const _f0 = /*@__PURE__*/ new Vector3(); - const _f1 = /*@__PURE__*/ new Vector3(); - const _f2 = /*@__PURE__*/ new Vector3(); + return _vector$a.distanceToSquared( point ); - const _center = /*@__PURE__*/ new Vector3(); - const _extents = /*@__PURE__*/ new Vector3(); - const _triangleNormal = /*@__PURE__*/ new Vector3(); - const _testAxis = /*@__PURE__*/ new Vector3(); + } - function satForAxes( axes, v0, v1, v2, extents ) { + distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { + // 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 - _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 ) { + _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + _segDir.copy( v1 ).sub( v0 ).normalize(); + _diff.copy( this.origin ).sub( _segCenter ); - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; - - } + const segExtent = v0.distanceTo( v1 ) * 0.5; + const a01 = - this.direction.dot( _segDir ); + const b0 = _diff.dot( this.direction ); + const b1 = - _diff.dot( _segDir ); + const c = _diff.lengthSq(); + const det = Math.abs( 1 - a01 * a01 ); + let s0, s1, sqrDist, extDet; - } + if ( det > 0 ) { - return true; + // The ray and segment are not parallel. - } + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - const _box$2 = /*@__PURE__*/ new Box3(); - const _v1$6 = /*@__PURE__*/ new Vector3(); - const _v2$3 = /*@__PURE__*/ new Vector3(); + if ( s0 >= 0 ) { - class Sphere { + if ( s1 >= - extDet ) { - constructor( center = new Vector3(), radius = - 1 ) { + if ( s1 <= extDet ) { - this.center = center; - this.radius = radius; + // region 0 + // Minimum at interior points of ray and segment. - } + const invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - set( center, radius ) { + } else { - this.center.copy( center ); - this.radius = radius; + // region 1 - return this; + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - setFromPoints( points, optionalCenter ) { + } else { - const center = this.center; + // region 5 - if ( optionalCenter !== undefined ) { + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - center.copy( optionalCenter ); + } - } else { + } else { - _box$2.setFromPoints( points ).getCenter( center ); + if ( s1 <= - extDet ) { - } + // region 4 - let maxRadiusSq = 0; + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - for ( let i = 0, il = points.length; i < il; i ++ ) { + } else if ( s1 <= extDet ) { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + // region 3 - } + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - this.radius = Math.sqrt( maxRadiusSq ); + } else { - return this; + // region 2 - } + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - copy( sphere ) { + } - this.center.copy( sphere.center ); - this.radius = sphere.radius; + } - return this; + } else { - } + // Ray and segment are parallel. - isEmpty() { + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - return ( this.radius < 0 ); + } - } + if ( optionalPointOnRay ) { - makeEmpty() { + optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); - this.center.set( 0, 0, 0 ); - this.radius = - 1; + } - return this; + if ( optionalPointOnSegment ) { - } + optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); - containsPoint( point ) { + } - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + return sqrDist; } - distanceToPoint( point ) { + intersectSphere( sphere, target ) { - return ( point.distanceTo( this.center ) - this.radius ); + _vector$a.subVectors( sphere.center, this.origin ); + const tca = _vector$a.dot( this.direction ); + const d2 = _vector$a.dot( _vector$a ) - tca * tca; + const radius2 = sphere.radius * sphere.radius; - } + if ( d2 > radius2 ) return null; - intersectsSphere( sphere ) { + const thc = Math.sqrt( radius2 - d2 ); - const radiusSum = this.radius + sphere.radius; + // t0 = first intersect point - entrance on front of sphere + const t0 = tca - thc; - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + // t1 = second intersect point - exit point on back of sphere + const t1 = tca + thc; - } + // test to see if t1 is behind the ray - if so, return null + if ( t1 < 0 ) return null; - intersectsBox( box ) { + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); - return box.intersectsSphere( this ); + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); } - intersectsPlane( plane ) { + intersectsSphere( sphere ) { - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); } - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + distanceToPlane( plane ) { - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); + const denominator = plane.normal.dot( this.direction ); - } + if ( denominator === 0 ) { - return target; + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - } + return 0; - getBoundingBox( target ) { + } - if ( this.isEmpty() ) { + // Null is preferable to undefined since undefined means.... it is undefined - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; + return null; } - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); + const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - return target; + // Return if the ray never intersects the plane - } + return t >= 0 ? t : null; - applyMatrix4( matrix ) { + } - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + intersectPlane( plane, target ) { - return this; + const t = this.distanceToPlane( plane ); - } + if ( t === null ) { - translate( offset ) { + return null; - this.center.add( offset ); + } - return this; + return this.at( t, target ); } - expandByPoint( point ) { + intersectsPlane( plane ) { - if ( this.isEmpty() ) { + // check if the ray lies on the plane first - this.center.copy( point ); + const distToPoint = plane.distanceToPoint( this.origin ); - this.radius = 0; + if ( distToPoint === 0 ) { - return this; + return true; } - _v1$6.subVectors( point, this.center ); + const denominator = plane.normal.dot( this.direction ); - const lengthSq = _v1$6.lengthSq(); + if ( denominator * distToPoint < 0 ) { - if ( lengthSq > ( this.radius * this.radius ) ) { + return true; - // calculate the minimal sphere + } - const length = Math.sqrt( lengthSq ); + // ray origin is behind the plane (and is pointing behind it) - const delta = ( length - this.radius ) * 0.5; + return false; - this.center.addScaledVector( _v1$6, delta / length ); + } - this.radius += delta; + intersectBox( box, target ) { - } + let tmin, tmax, tymin, tymax, tzmin, tzmax; - return this; + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + const origin = this.origin; - union( sphere ) { + if ( invdirx >= 0 ) { - if ( sphere.isEmpty() ) { + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - return this; + } else { + + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; } - if ( this.isEmpty() ) { + if ( invdiry >= 0 ) { - this.copy( sphere ); + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - return this; + } else { + + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; } - if ( this.center.equals( sphere.center ) === true ) { + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - this.radius = Math.max( this.radius, sphere.radius ); + if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; - } else { + if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; - _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); + if ( invdirz >= 0 ) { - this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); + } else { - } + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - return this; + } - } + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - equals( sphere ) { + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - } + //return point closest to the ray (positive side) - clone() { + if ( tmax < 0 ) return null; - return new this.constructor().copy( this ); + return this.at( tmin >= 0 ? tmin : tmax, target ); } - } - - const _vector$a = /*@__PURE__*/ new Vector3(); - const _segCenter = /*@__PURE__*/ new Vector3(); - const _segDir = /*@__PURE__*/ new Vector3(); - const _diff = /*@__PURE__*/ new Vector3(); - - const _edge1 = /*@__PURE__*/ new Vector3(); - const _edge2 = /*@__PURE__*/ new Vector3(); - const _normal$1 = /*@__PURE__*/ new Vector3(); + intersectsBox( box ) { - class Ray { + return this.intersectBox( box, _vector$a ) !== null; - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + } - this.origin = origin; - this.direction = direction; + intersectTriangle( a, b, c, backfaceCulling, target ) { - } + // Compute the offset origin, edges, and normal. - set( origin, direction ) { + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - this.origin.copy( origin ); - this.direction.copy( direction ); + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal$1.crossVectors( _edge1, _edge2 ); - return this; + // 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 ) { - copy( ray ) { + if ( backfaceCulling ) return null; + sign = 1; - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + } else if ( DdN < 0 ) { - return this; + sign = - 1; + DdN = - DdN; - } + } else { - at( t, target ) { + return null; - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + } - } + _diff.subVectors( this.origin, a ); + const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - lookAt( v ) { + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - this.direction.copy( v ).sub( this.origin ).normalize(); + return null; - return this; + } - } + const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - recast( t ) { + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - this.origin.copy( this.at( t, _vector$a ) ); + return null; - return this; + } - } + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - closestPointToPoint( point, target ) { + return null; - target.subVectors( point, this.origin ); + } - const directionDistance = target.dot( this.direction ); + // Line intersects triangle, check if ray does. + const QdN = - sign * _diff.dot( _normal$1 ); - if ( directionDistance < 0 ) { + // t < 0, no intersection + if ( QdN < 0 ) { - return target.copy( this.origin ); + return null; } - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + // Ray intersects triangle. + return this.at( QdN / DdN, target ); } - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } + applyMatrix4( matrix4 ) { - distanceSqToPoint( point ) { + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); + return this; - // point behind the ray + } - if ( directionDistance < 0 ) { + equals( ray ) { - return this.origin.distanceToSquared( point ); + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - } + } - _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + clone() { - return _vector$a.distanceToSquared( point ); + return new this.constructor().copy( this ); } - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // 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 - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); + } - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; + class Matrix4 { - if ( det > 0 ) { + constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - // The ray and segment are not parallel. + Matrix4.prototype.isMatrix4 = true; - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + this.elements = [ - if ( s0 >= 0 ) { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 >= - extDet ) { + ]; - if ( s1 <= extDet ) { + if ( n11 !== undefined ) { - // region 0 - // Minimum at interior points of ray and segment. + this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + } - } else { + } - // region 1 + set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + const te = this.elements; - } + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - } else { + return this; - // region 5 + } - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + identity() { - } + this.set( - } else { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 <= - extDet ) { + ); - // region 4 + return this; - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } else if ( s1 <= extDet ) { + clone() { - // region 3 + return new Matrix4().fromArray( this.elements ); - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } - } else { + copy( m ) { - // region 2 + const te = this.elements; + const me = m.elements; - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - } + return this; - } + } - } else { + copyPosition( m ) { - // Ray and segment are parallel. + const te = this.elements, me = m.elements; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; - } + return this; - if ( optionalPointOnRay ) { + } - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + setFromMatrix3( m ) { - } + const me = m.elements; - if ( optionalPointOnSegment ) { + this.set( - optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); + me[ 0 ], me[ 3 ], me[ 6 ], 0, + me[ 1 ], me[ 4 ], me[ 7 ], 0, + me[ 2 ], me[ 5 ], me[ 8 ], 0, + 0, 0, 0, 1 - } + ); - return sqrDist; + return this; } - intersectSphere( sphere, target ) { + extractBasis( xAxis, yAxis, zAxis ) { - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); - if ( d2 > radius2 ) return null; + return this; - const thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; + makeBasis( xAxis, yAxis, zAxis ) { - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; + 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 + ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + return this; - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); + } - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); + extractRotation( m ) { - } + // this method does not support reflection matrices - intersectsSphere( sphere ) { + const te = this.elements; + const me = m.elements; - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; + + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; + + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; + + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; } - distanceToPlane( plane ) { + makeRotationFromEuler( euler ) { - const denominator = plane.normal.dot( this.direction ); + const te = this.elements; - if ( denominator === 0 ) { + const x = euler.x, y = euler.y, z = euler.z; + const a = Math.cos( x ), b = Math.sin( x ); + const c = Math.cos( y ), d = Math.sin( y ); + const e = Math.cos( z ), f = Math.sin( z ); - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + if ( euler.order === 'XYZ' ) { - return 0; + const ae = a * e, af = a * f, be = b * e, bf = b * f; - } + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - // Null is preferable to undefined since undefined means.... it is undefined + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - return null; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - } + } else if ( euler.order === 'YXZ' ) { - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + const ce = c * e, cf = c * f, de = d * e, df = d * f; - // Return if the ray never intersects the plane + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - return t >= 0 ? t : null; + 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; - intersectPlane( plane, target ) { + } else if ( euler.order === 'ZXY' ) { - const t = this.distanceToPlane( plane ); + const ce = c * e, cf = c * f, de = d * e, df = d * f; - if ( t === null ) { + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - return null; + 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; - return this.at( t, target ); + } else if ( euler.order === 'ZYX' ) { - } + const ae = a * e, af = a * f, be = b * e, bf = b * f; - intersectsPlane( plane ) { + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - // check if the ray lies on the plane first + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - const distToPoint = plane.distanceToPoint( this.origin ); + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - if ( distToPoint === 0 ) { + } else if ( euler.order === 'YZX' ) { - return true; + 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; - const denominator = plane.normal.dot( this.direction ); + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - if ( denominator * distToPoint < 0 ) { + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - return true; + } else if ( euler.order === 'XZY' ) { - } + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // ray origin is behind the plane (and is pointing behind it) + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - return false; + 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; - intersectBox( box, target ) { + } - let tmin, tmax, tymin, tymax, tzmin, tzmax; + // bottom row + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + // last column + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - const origin = this.origin; + return this; - if ( invdirx >= 0 ) { + } - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + makeRotationFromQuaternion( q ) { - } else { + return this.compose( _zero, q, _one ); - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + } - } + lookAt( eye, target, up ) { - if ( invdiry >= 0 ) { + const te = this.elements; - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + _z.subVectors( eye, target ); - } else { + if ( _z.lengthSq() === 0 ) { - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + // eye and target are in the same position - } + _z.z = 1; - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + } - if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; + if ( _x.lengthSq() === 0 ) { - if ( invdirz >= 0 ) { + // up and z are parallel - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + if ( Math.abs( up.z ) === 1 ) { - } else { + _z.x += 0.0001; - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + } else { - } + _z.z += 0.0001; - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + } - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + } - //return point closest to the ray (positive side) + _x.normalize(); + _y.crossVectors( _z, _x ); - if ( tmax < 0 ) return null; + te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; + te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; + te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - return this.at( tmin >= 0 ? tmin : tmax, target ); + return this; } - intersectsBox( box ) { + multiply( m ) { - return this.intersectBox( box, _vector$a ) !== null; + return this.multiplyMatrices( this, m ); } - intersectTriangle( a, b, c, backfaceCulling, target ) { + premultiply( m ) { - // Compute the offset origin, edges, and normal. + return this.multiplyMatrices( m, this ); - // 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 ) { + multiplyMatrices( a, b ) { - if ( backfaceCulling ) return null; - sign = 1; + const ae = a.elements; + const be = b.elements; + const te = this.elements; - } else if ( DdN < 0 ) { + const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - sign = - 1; - DdN = - DdN; + const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - } else { + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - return null; + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - } + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + return this; - return null; + } - } + multiplyScalar( s ) { - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); + const te = this.elements; - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - return null; + return this; - } + } - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + determinant() { - return null; + const te = this.elements; - } + const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - // t < 0, no intersection - if ( QdN < 0 ) { + 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 + ) - return null; + ); - } + } - // Ray intersects triangle. - return this.at( QdN / DdN, target ); + transpose() { - } + const te = this.elements; + let tmp; - applyMatrix4( matrix4 ) { + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; return this; } - equals( ray ) { + setPosition( x, y, z ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + const te = this.elements; - } + if ( x.isVector3 ) { - clone() { + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; - return new this.constructor().copy( this ); + } else { + + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; + + } + + return this; } - } + invert() { - class Matrix4 { + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + const te = this.elements, - constructor() { + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], + n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], + n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], + n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - Matrix4.prototype.isMatrix4 = true; + 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; - this.elements = [ + const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - ]; + const detInv = 1 / det; - } + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - const te = this.elements; + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; return this; } - identity() { - - this.set( + scale( v ) { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + const te = this.elements; + const x = v.x, y = v.y, z = v.z; - ); + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; } - clone() { + getMaxScaleOnAxis() { - return new Matrix4().fromArray( this.elements ); + const te = this.elements; + + const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); } - copy( m ) { + makeTranslation( x, y, z ) { - const te = this.elements; - const me = m.elements; + if ( x.isVector3 ) { - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; + this.set( - return this; + 1, 0, 0, x.x, + 0, 1, 0, x.y, + 0, 0, 1, x.z, + 0, 0, 0, 1 - } + ); - copyPosition( m ) { + } else { - const te = this.elements, me = m.elements; + this.set( - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + } return this; } - setFromMatrix3( m ) { + makeRotationX( theta ) { - const me = m.elements; + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, 0, 0, 0, 1 ); @@ -5940,2377 +6302,2635 @@ } - extractBasis( xAxis, yAxis, zAxis ) { + makeRotationY( theta ) { - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 + + ); return this; } - makeBasis( xAxis, yAxis, zAxis ) { + makeRotationZ( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1 + ); return this; } - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; + makeRotationAxis( axis, angle ) { - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + // Based on http://www.gamedev.net/reference/articles/article1199.asp - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; + const c = Math.cos( angle ); + const s = Math.sin( angle ); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; + this.set( - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + 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 - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + ); return this; } - makeRotationFromEuler( euler ) { - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); + makeScale( x, y, z ) { - if ( euler.order === 'XYZ' ) { + this.set( - const ae = a * e, af = a * f, be = b * e, bf = b * f; + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - 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; + return this; - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; + } - } else if ( euler.order === 'YXZ' ) { + makeShear( xy, xz, yx, yz, zx, zy ) { - const ce = c * e, cf = c * f, de = d * e, df = d * f; + this.set( - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; + 1, yx, zx, 0, + xy, 1, zy, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 - 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; + return this; - } else if ( euler.order === 'ZXY' ) { + } - const ce = c * e, cf = c * f, de = d * e, df = d * f; + compose( position, quaternion, scale ) { - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; + const te = this.elements; - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; + const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; + const sx = scale.x, sy = scale.y, sz = scale.z; - } else if ( euler.order === 'ZYX' ) { + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; - const ae = a * e, af = a * f, be = b * e, bf = b * f; + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; + return this; - } else if ( euler.order === 'YZX' ) { + } - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + decompose( position, quaternion, scale ) { - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; + const te = this.elements; - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; + let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if ( det < 0 ) sx = - sx; - } else if ( euler.order === 'XZY' ) { + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + // scale the rotation part + _m1$2.copy( this ); - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; + _m1$2.elements[ 0 ] *= invSX; + _m1$2.elements[ 1 ] *= invSX; + _m1$2.elements[ 2 ] *= invSX; - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; + _m1$2.elements[ 4 ] *= invSY; + _m1$2.elements[ 5 ] *= invSY; + _m1$2.elements[ 6 ] *= invSY; - } + _m1$2.elements[ 8 ] *= invSZ; + _m1$2.elements[ 9 ] *= invSZ; + _m1$2.elements[ 10 ] *= invSZ; - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + quaternion.setFromRotationMatrix( _m1$2 ); - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + scale.x = sx; + scale.y = sy; + scale.z = sz; return this; } - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); + makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - } + const te = this.elements; + const x = 2 * near / ( right - left ); + const y = 2 * near / ( top - bottom ); - lookAt( eye, target, up ) { + const a = ( right + left ) / ( right - left ); + const b = ( top + bottom ) / ( top - bottom ); - const te = this.elements; + let c, d; - _z.subVectors( eye, target ); + if ( coordinateSystem === WebGLCoordinateSystem ) { - if ( _z.lengthSq() === 0 ) { + c = - ( far + near ) / ( far - near ); + d = ( - 2 * far * near ) / ( far - near ); - // eye and target are in the same position + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - _z.z = 1; + c = - far / ( far - near ); + d = ( - far * near ) / ( far - near ); - } + } else { - _z.normalize(); - _x.crossVectors( up, _z ); + throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); - if ( _x.lengthSq() === 0 ) { + } - // up and z are parallel + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - if ( Math.abs( up.z ) === 1 ) { + return this; - _z.x += 0.0001; + } - } else { + makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - _z.z += 0.0001; - - } + const te = this.elements; + const w = 1.0 / ( right - left ); + const h = 1.0 / ( top - bottom ); + const p = 1.0 / ( far - near ); - _z.normalize(); - _x.crossVectors( up, _z ); + const x = ( right + left ) * w; + const y = ( top + bottom ) * h; - } + let z, zInv; - _x.normalize(); - _y.crossVectors( _z, _x ); + if ( coordinateSystem === WebGLCoordinateSystem ) { - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; + z = ( far + near ) * p; + zInv = - 2 * p; - return this; + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - } + z = near * p; + zInv = - 1 * p; - multiply( m ) { + } else { - return this.multiplyMatrices( this, m ); + throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); - } + } - premultiply( m ) { + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - return this.multiplyMatrices( m, this ); + return this; } - multiplyMatrices( a, b ) { + equals( matrix ) { - const ae = a.elements; - const be = b.elements; const te = this.elements; + const me = matrix.elements; - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; + for ( let i = 0; i < 16; i ++ ) { - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; + if ( te[ i ] !== me[ i ] ) return false; - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + } - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + return true; - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + } - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + fromArray( array, offset = 0 ) { + + for ( let i = 0; i < 16; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } return this; } - multiplyScalar( s ) { + toArray( array = [], offset = 0 ) { const te = this.elements; - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - return this; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; + + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; + + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; + + return array; } - determinant() { + } - const te = this.elements; + const _v1$5 = /*@__PURE__*/ new Vector3(); + const _m1$2 = /*@__PURE__*/ new Matrix4(); + const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); + const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); + const _x = /*@__PURE__*/ new Vector3(); + const _y = /*@__PURE__*/ new Vector3(); + const _z = /*@__PURE__*/ new Vector3(); - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + const _matrix$1 = /*@__PURE__*/ new Matrix4(); + const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + class Euler { - 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 - ) + constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { - ); + this.isEuler = true; + + this._x = x; + this._y = y; + this._z = z; + this._order = order; } - transpose() { + get x() { - const te = this.elements; - let tmp; + return this._x; - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; + } - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; + set x( value ) { - return this; + this._x = value; + this._onChangeCallback(); } - setPosition( x, y, z ) { + get y() { - const te = this.elements; + return this._y; - if ( x.isVector3 ) { + } - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; + set y( value ) { - } else { + this._y = value; + this._onChangeCallback(); - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; + } - } + get z() { - return this; + return this._z; } - invert() { + set z( value ) { - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, + this._z = value; + this._onChangeCallback(); - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], + } - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + get order() { - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + return this._order; - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + } - const detInv = 1 / det; + set order( value ) { - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + this._order = value; + this._onChangeCallback(); - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + } - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + set( x, y, z, order = this._order ) { - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + this._x = x; + this._y = y; + this._z = z; + this._order = order; + + this._onChangeCallback(); return this; } - scale( v ) { - - const te = this.elements; - const x = v.x, y = v.y, z = v.z; - - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; + clone() { - return this; + return new this.constructor( this._x, this._y, this._z, this._order ); } - getMaxScaleOnAxis() { + copy( euler ) { - const te = this.elements; + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._onChangeCallback(); + + return this; + + } + + setFromRotationMatrix( m, order = this._order, update = true ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + 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': + + this._y = Math.asin( clamp( m13, - 1, 1 ) ); + + if ( Math.abs( m13 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + break; + + case 'YXZ': + + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + + if ( Math.abs( m23 ) < 0.9999999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + break; + + case 'ZXY': + + this._x = Math.asin( clamp( m32, - 1, 1 ) ); + + if ( Math.abs( m32 ) < 0.9999999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + break; + + case 'ZYX': + + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + + if ( Math.abs( m31 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + break; + + case 'YZX': + + this._z = Math.asin( clamp( m21, - 1, 1 ) ); + + if ( Math.abs( m21 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + break; + + case 'XZY': + + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + + if ( Math.abs( m12 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + break; + + default: + + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + + } + + this._order = order; + + if ( update === true ) this._onChangeCallback(); + + return this; + + } + + setFromQuaternion( q, order, update ) { + + _matrix$1.makeRotationFromQuaternion( q ); + + return this.setFromRotationMatrix( _matrix$1, order, update ); + + } + + setFromVector3( v, order = this._order ) { + + return this.set( v.x, v.y, v.z, order ); + + } + + reorder( newOrder ) { + + // WARNING: this discards revolution information -bhouston + + _quaternion$3.setFromEuler( this ); + + return this.setFromQuaternion( _quaternion$3, newOrder ); + + } + + equals( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + } + + 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; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + 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 ) { + + this.mask = ( 1 << channel | 0 ) >>> 0; + + } + + enable( channel ) { + + this.mask |= 1 << channel | 0; + + } + + enableAll() { + + this.mask = 0xffffffff | 0; + + } + + toggle( channel ) { + + this.mask ^= 1 << channel | 0; + + } + + disable( channel ) { + + this.mask &= ~ ( 1 << channel | 0 ); + + } + + disableAll() { + + this.mask = 0; + + } + + test( layers ) { + + return ( this.mask & layers.mask ) !== 0; + + } + + isEnabled( channel ) { + + return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + + } + + } + + let _object3DId = 0; + + const _v1$4 = /*@__PURE__*/ new Vector3(); + const _q1 = /*@__PURE__*/ new Quaternion(); + const _m1$1 = /*@__PURE__*/ new Matrix4(); + const _target = /*@__PURE__*/ new Vector3(); + + const _position$3 = /*@__PURE__*/ new Vector3(); + const _scale$2 = /*@__PURE__*/ new Vector3(); + const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + + const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); + const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + + const _addedEvent = { type: 'added' }; + const _removedEvent = { type: 'removed' }; + + class Object3D extends EventDispatcher { + + constructor() { + + super(); + + this.isObject3D = true; + + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = Object3D.DEFAULT_UP.clone(); + + const position = new Vector3(); + const rotation = new Euler(); + const quaternion = new Quaternion(); + const scale = new Vector3( 1, 1, 1 ); + + function onRotationChange() { + + quaternion.setFromEuler( rotation, false ); + + } + + function onQuaternionChange() { + + rotation.setFromQuaternion( quaternion, undefined, false ); + + } + + 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() + } + } ); - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; - } + this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer + this.matrixWorldNeedsUpdate = false; - makeTranslation( x, y, z ) { + this.layers = new Layers(); + this.visible = true; - this.set( + this.castShadow = false; + this.receiveShadow = false; - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + this.frustumCulled = true; + this.renderOrder = 0; - ); + this.animations = []; - return this; + this.userData = {}; } - makeRotationX( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); + onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - this.set( + onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - ); + onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - return this; + applyMatrix4( matrix ) { - } + if ( this.matrixAutoUpdate ) this.updateMatrix(); - makeRotationY( theta ) { + this.matrix.premultiply( matrix ); - const c = Math.cos( theta ), s = Math.sin( theta ); + this.matrix.decompose( this.position, this.quaternion, this.scale ); - this.set( + } - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + applyQuaternion( q ) { - ); + this.quaternion.premultiply( q ); return this; } - makeRotationZ( theta ) { + setRotationFromAxisAngle( axis, angle ) { - const c = Math.cos( theta ), s = Math.sin( theta ); + // assumes axis is normalized - this.set( + this.quaternion.setFromAxisAngle( axis, angle ); - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + } - ); + setRotationFromEuler( euler ) { - return this; + this.quaternion.setFromEuler( euler, true ); } - makeRotationAxis( axis, angle ) { + setRotationFromMatrix( m ) { - // Based on http://www.gamedev.net/reference/articles/article1199.asp + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; + this.quaternion.setFromRotationMatrix( m ); - 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 + setRotationFromQuaternion( q ) { - ); + // assumes q is normalized - return this; + this.quaternion.copy( q ); } - makeScale( x, y, z ) { + rotateOnAxis( axis, angle ) { - this.set( + // rotate object on axis in object space + // axis is assumed to be normalized - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + _q1.setFromAxisAngle( axis, angle ); - ); + this.quaternion.multiply( _q1 ); return this; } - makeShear( xy, xz, yx, yz, zx, zy ) { + rotateOnWorldAxis( axis, angle ) { - this.set( + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 + _q1.setFromAxisAngle( axis, angle ); - ); + this.quaternion.premultiply( _q1 ); return this; } - compose( position, quaternion, scale ) { - - const te = this.elements; - - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; - - const sx = scale.x, sy = scale.y, sz = scale.z; - - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; - - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; - - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; - - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; + rotateX( angle ) { - return this; + return this.rotateOnAxis( _xAxis, angle ); } - decompose( position, quaternion, scale ) { - - const te = this.elements; - - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + rotateY( angle ) { - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; + return this.rotateOnAxis( _yAxis, angle ); - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; + } - // scale the rotation part - _m1$2.copy( this ); + rotateZ( angle ) { - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; + return this.rotateOnAxis( _zAxis, angle ); - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; + } - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; + translateOnAxis( axis, distance ) { - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; + // translate object by distance along axis in object space + // axis is assumed to be normalized - quaternion.setFromRotationMatrix( _m1$2 ); + _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - scale.x = sx; - scale.y = sy; - scale.z = sz; + this.position.add( _v1$4.multiplyScalar( distance ) ); return this; } - makePerspective( left, right, top, bottom, near, far ) { + translateX( distance ) { - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); + return this.translateOnAxis( _xAxis, distance ); - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - const c = - ( far + near ) / ( far - near ); - const d = - 2 * far * near / ( far - near ); + } - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + translateY( distance ) { - return this; + return this.translateOnAxis( _yAxis, distance ); } - makeOrthographic( left, right, top, bottom, near, far ) { + translateZ( distance ) { - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); + return this.translateOnAxis( _zAxis, distance ); - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - const z = ( far + near ) * p; + } + + localToWorld( vector ) { - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + this.updateWorldMatrix( true, false ); - return this; + return vector.applyMatrix4( this.matrixWorld ); } - equals( matrix ) { + worldToLocal( vector ) { - const te = this.elements; - const me = matrix.elements; + this.updateWorldMatrix( true, false ); - for ( let i = 0; i < 16; i ++ ) { + return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - if ( te[ i ] !== me[ i ] ) return false; + } - } + lookAt( x, y, z ) { - return true; + // This method does not support objects having non-uniformly-scaled parent(s) - } + if ( x.isVector3 ) { - fromArray( array, offset = 0 ) { + _target.copy( x ); - for ( let i = 0; i < 16; i ++ ) { + } else { - this.elements[ i ] = array[ i + offset ]; + _target.set( x, y, z ); } - return this; + const parent = this.parent; - } + this.updateWorldMatrix( true, false ); - toArray( array = [], offset = 0 ) { + _position$3.setFromMatrixPosition( this.matrixWorld ); - const te = this.elements; + if ( this.isCamera || this.isLight ) { - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; + _m1$1.lookAt( _position$3, _target, this.up ); - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; + } else { + + _m1$1.lookAt( _target, _position$3, this.up ); - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; + } - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; + this.quaternion.setFromRotationMatrix( _m1$1 ); - return array; + if ( parent ) { - } + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.invert() ); - } + } - const _v1$5 = /*@__PURE__*/ new Vector3(); - const _m1$2 = /*@__PURE__*/ new Matrix4(); - const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); - const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); - const _x = /*@__PURE__*/ new Vector3(); - const _y = /*@__PURE__*/ new Vector3(); - const _z = /*@__PURE__*/ new Vector3(); + } - const _matrix$1 = /*@__PURE__*/ new Matrix4(); - const _quaternion$3 = /*@__PURE__*/ new Quaternion(); + add( object ) { - class Euler { + if ( arguments.length > 1 ) { - constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { + for ( let i = 0; i < arguments.length; i ++ ) { - this.isEuler = true; + this.add( arguments[ i ] ); - this._x = x; - this._y = y; - this._z = z; - this._order = order; + } - } + return this; - get x() { + } - return this._x; + if ( object === this ) { - } + console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); + return this; - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + if ( object && object.isObject3D ) { - } + if ( object.parent !== null ) { - get y() { + object.parent.remove( object ); - return this._y; + } - } + object.parent = this; + this.children.push( object ); - set y( value ) { + object.dispatchEvent( _addedEvent ); - this._y = value; - this._onChangeCallback(); + } else { - } + console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - get z() { + } - return this._z; + return this; } - set z( value ) { + remove( object ) { - this._z = value; - this._onChangeCallback(); + if ( arguments.length > 1 ) { - } + for ( let i = 0; i < arguments.length; i ++ ) { - get order() { + this.remove( arguments[ i ] ); - return this._order; + } - } + return this; - set order( value ) { + } - this._order = value; - this._onChangeCallback(); + const index = this.children.indexOf( object ); - } + if ( index !== - 1 ) { - set( x, y, z, order = this._order ) { + object.parent = null; + this.children.splice( index, 1 ); - this._x = x; - this._y = y; - this._z = z; - this._order = order; + object.dispatchEvent( _removedEvent ); - this._onChangeCallback(); + } return this; } - clone() { - - return new this.constructor( this._x, this._y, this._z, this._order ); + removeFromParent() { - } + const parent = this.parent; - copy( euler ) { + if ( parent !== null ) { - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + parent.remove( this ); - this._onChangeCallback(); + } return this; } - setFromRotationMatrix( m, order = this._order, update = true ) { + clear() { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + return this.remove( ... this.children ); - 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 ) { + attach( object ) { - case 'XYZ': + // adds object as a child of this, while maintaining the object's world transform - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - if ( Math.abs( m13 ) < 0.9999999 ) { + this.updateWorldMatrix( true, false ); - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + _m1$1.copy( this.matrixWorld ).invert(); - } else { + if ( object.parent !== null ) { - this._x = Math.atan2( m32, m22 ); - this._z = 0; + object.parent.updateWorldMatrix( true, false ); - } + _m1$1.multiply( object.parent.matrixWorld ); - break; + } - case 'YXZ': + object.applyMatrix4( _m1$1 ); - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + this.add( object ); - if ( Math.abs( m23 ) < 0.9999999 ) { + object.updateWorldMatrix( false, true ); - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + return this; - } else { + } - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + getObjectById( id ) { - } + return this.getObjectByProperty( 'id', id ); - break; + } - case 'ZXY': + getObjectByName( name ) { - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + return this.getObjectByProperty( 'name', name ); - if ( Math.abs( m32 ) < 0.9999999 ) { + } - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + getObjectByProperty( name, value ) { - } else { + if ( this[ name ] === value ) return this; - this._y = 0; - this._z = Math.atan2( m21, m11 ); + for ( let i = 0, l = this.children.length; i < l; i ++ ) { - } + const child = this.children[ i ]; + const object = child.getObjectByProperty( name, value ); - break; + if ( object !== undefined ) { - case 'ZYX': + return object; - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + } - if ( Math.abs( m31 ) < 0.9999999 ) { + } - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + return undefined; - } else { + } - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + getObjectsByProperty( name, value, result = [] ) { - } + if ( this[ name ] === value ) result.push( this ); - break; + const children = this.children; - case 'YZX': + for ( let i = 0, l = children.length; i < l; i ++ ) { - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + children[ i ].getObjectsByProperty( name, value, result ); - if ( Math.abs( m21 ) < 0.9999999 ) { + } - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + return result; - } else { + } - this._x = 0; - this._y = Math.atan2( m13, m33 ); + getWorldPosition( target ) { - } + this.updateWorldMatrix( true, false ); - break; + return target.setFromMatrixPosition( this.matrixWorld ); - case 'XZY': + } - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + getWorldQuaternion( target ) { - if ( Math.abs( m12 ) < 0.9999999 ) { + this.updateWorldMatrix( true, false ); - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + this.matrixWorld.decompose( _position$3, target, _scale$2 ); - } else { + return target; - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + } - } + getWorldScale( target ) { - break; + this.updateWorldMatrix( true, false ); - default: + this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + return target; - } + } - this._order = order; + getWorldDirection( target ) { - if ( update === true ) this._onChangeCallback(); + this.updateWorldMatrix( true, false ); - return this; + const e = this.matrixWorld.elements; + + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + + } + + raycast( /* raycaster, intersects */ ) {} + + traverse( callback ) { + + callback( this ); - } + const children = this.children; - setFromQuaternion( q, order, update ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - _matrix$1.makeRotationFromQuaternion( q ); + children[ i ].traverse( callback ); - return this.setFromRotationMatrix( _matrix$1, order, update ); + } } - setFromVector3( v, order = this._order ) { + traverseVisible( callback ) { - return this.set( v.x, v.y, v.z, order ); + if ( this.visible === false ) return; - } + callback( this ); - reorder( newOrder ) { + const children = this.children; - // WARNING: this discards revolution information -bhouston + for ( let i = 0, l = children.length; i < l; i ++ ) { - _quaternion$3.setFromEuler( this ); + children[ i ].traverseVisible( callback ); - return this.setFromQuaternion( _quaternion$3, newOrder ); + } } - equals( euler ) { - - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + traverseAncestors( callback ) { - } + const parent = this.parent; - fromArray( array ) { + if ( parent !== null ) { - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + callback( parent ); - this._onChangeCallback(); + parent.traverseAncestors( callback ); - return this; + } } - toArray( array = [], offset = 0 ) { + updateMatrix() { - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + this.matrix.compose( this.position, this.quaternion, this.scale ); - return array; + this.matrixWorldNeedsUpdate = true; } - _onChange( callback ) { - - this._onChangeCallback = callback; + updateMatrixWorld( force ) { - return this; + if ( this.matrixAutoUpdate ) this.updateMatrix(); - } + if ( this.matrixWorldNeedsUpdate || force ) { - _onChangeCallback() {} + if ( this.parent === null ) { - *[ Symbol.iterator ]() { + this.matrixWorld.copy( this.matrix ); - yield this._x; - yield this._y; - yield this._z; - yield this._order; + } else { - } + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - // @deprecated since r138, 02cf0df1cb4575d5842fef9c85bb5a89fe020d53 + } - toVector3() { + this.matrixWorldNeedsUpdate = false; - console.error( 'THREE.Euler: .toVector3() has been removed. Use Vector3.setFromEuler() instead' ); + force = true; - } + } - } + // update children - Euler.DefaultOrder = 'XYZ'; - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + const children = this.children; - class Layers { + for ( let i = 0, l = children.length; i < l; i ++ ) { - constructor() { + const child = children[ i ]; - this.mask = 1 | 0; + if ( child.matrixWorldAutoUpdate === true || force === true ) { - } + child.updateMatrixWorld( force ); - set( channel ) { + } - this.mask = ( 1 << channel | 0 ) >>> 0; + } } - enable( channel ) { + updateWorldMatrix( updateParents, updateChildren ) { - this.mask |= 1 << channel | 0; + const parent = this.parent; - } + if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - enableAll() { + parent.updateWorldMatrix( true, false ); - this.mask = 0xffffffff | 0; + } - } + if ( this.matrixAutoUpdate ) this.updateMatrix(); - toggle( channel ) { + if ( this.parent === null ) { - this.mask ^= 1 << channel | 0; + this.matrixWorld.copy( this.matrix ); - } + } else { - disable( channel ) { + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - this.mask &= ~ ( 1 << channel | 0 ); + } - } + // update children - disableAll() { + if ( updateChildren === true ) { - this.mask = 0; + const children = this.children; - } + for ( let i = 0, l = children.length; i < l; i ++ ) { - test( layers ) { + const child = children[ i ]; - return ( this.mask & layers.mask ) !== 0; + if ( child.matrixWorldAutoUpdate === true ) { - } + child.updateWorldMatrix( false, true ); - isEnabled( channel ) { + } - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + } + + } } - } + toJSON( meta ) { - let _object3DId = 0; + // meta is a string when called from JSON.stringify + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - const _v1$4 = /*@__PURE__*/ new Vector3(); - const _q1 = /*@__PURE__*/ new Quaternion(); - const _m1$1 = /*@__PURE__*/ new Matrix4(); - const _target = /*@__PURE__*/ new Vector3(); + const output = {}; - const _position$3 = /*@__PURE__*/ new Vector3(); - const _scale$2 = /*@__PURE__*/ new Vector3(); - const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); - const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {}, + skeletons: {}, + animations: {}, + nodes: {} + }; - const _addedEvent = { type: 'added' }; - const _removedEvent = { type: 'removed' }; + output.metadata = { + version: 4.6, + type: 'Object', + generator: 'Object3D.toJSON' + }; - class Object3D extends EventDispatcher { + } - constructor() { + // standard Object3D serialization - super(); + const object = {}; - this.isObject3D = true; + object.uuid = this.uuid; + object.type = this.type; - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + if ( this.name !== '' ) object.name = this.name; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + if ( this.frustumCulled === false ) object.frustumCulled = false; + if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; + if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; - this.uuid = generateUUID(); + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); + object.up = this.up.toArray(); - this.name = ''; - this.type = 'Object3D'; + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - this.parent = null; - this.children = []; + // object specific properties - this.up = Object3D.DefaultUp.clone(); + if ( this.isInstancedMesh ) { - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); + if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - function onRotationChange() { + } - quaternion.setFromEuler( rotation, false ); + if ( this.isBatchedMesh ) { - } + object.type = 'BatchedMesh'; + object.perObjectFrustumCulled = this.perObjectFrustumCulled; + object.sortObjects = this.sortObjects; - function onQuaternionChange() { + object.drawRanges = this._drawRanges; + object.reservedRanges = this._reservedRanges; - rotation.setFromQuaternion( quaternion, undefined, false ); + 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() + } ) ); - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); + object.maxGeometryCount = this._maxGeometryCount; + object.maxVertexCount = this._maxVertexCount; + object.maxIndexCount = this._maxIndexCount; - 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() - } - } ); + object.geometryInitialized = this._geometryInitialized; + object.geometryCount = this._geometryCount; - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); + object.matricesTexture = this._matricesTexture.toJSON( meta ); - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + if ( this.boundingSphere !== null ) { - this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer + object.boundingSphere = { + center: object.boundingSphere.center.toArray(), + radius: object.boundingSphere.radius + }; - this.layers = new Layers(); - this.visible = true; + } - this.castShadow = false; - this.receiveShadow = false; + if ( this.boundingBox !== null ) { - this.frustumCulled = true; - this.renderOrder = 0; + object.boundingBox = { + min: object.boundingBox.min.toArray(), + max: object.boundingBox.max.toArray() + }; - this.animations = []; + } + + } + + // - this.userData = {}; + function serialize( library, element ) { - } + if ( library[ element.uuid ] === undefined ) { - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} + library[ element.uuid ] = element.toJSON( meta ); - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} + } - applyMatrix4( matrix ) { + return element.uuid; - if ( this.matrixAutoUpdate ) this.updateMatrix(); + } - this.matrix.premultiply( matrix ); + if ( this.isScene ) { - this.matrix.decompose( this.position, this.quaternion, this.scale ); + if ( this.background ) { - } + if ( this.background.isColor ) { - applyQuaternion( q ) { + object.background = this.background.toJSON(); - this.quaternion.premultiply( q ); + } else if ( this.background.isTexture ) { - return this; + object.background = this.background.toJSON( meta ).uuid; - } + } - setRotationFromAxisAngle( axis, angle ) { + } - // assumes axis is normalized + if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - this.quaternion.setFromAxisAngle( axis, angle ); + object.environment = this.environment.toJSON( meta ).uuid; - } + } - setRotationFromEuler( euler ) { + } else if ( this.isMesh || this.isLine || this.isPoints ) { - this.quaternion.setFromEuler( euler, true ); + object.geometry = serialize( meta.geometries, this.geometry ); - } + const parameters = this.geometry.parameters; - setRotationFromMatrix( m ) { + if ( parameters !== undefined && parameters.shapes !== undefined ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + const shapes = parameters.shapes; - this.quaternion.setFromRotationMatrix( m ); + if ( Array.isArray( shapes ) ) { - } + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - setRotationFromQuaternion( q ) { + const shape = shapes[ i ]; - // assumes q is normalized + serialize( meta.shapes, shape ); - this.quaternion.copy( q ); + } - } + } else { - rotateOnAxis( axis, angle ) { + serialize( meta.shapes, shapes ); - // rotate object on axis in object space - // axis is assumed to be normalized + } - _q1.setFromAxisAngle( axis, angle ); + } - this.quaternion.multiply( _q1 ); + } - return this; + if ( this.isSkinnedMesh ) { - } + object.bindMode = this.bindMode; + object.bindMatrix = this.bindMatrix.toArray(); - rotateOnWorldAxis( axis, angle ) { + if ( this.skeleton !== undefined ) { - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + serialize( meta.skeletons, this.skeleton ); - _q1.setFromAxisAngle( axis, angle ); + object.skeleton = this.skeleton.uuid; - this.quaternion.premultiply( _q1 ); + } - return this; + } - } + if ( this.material !== undefined ) { - rotateX( angle ) { + if ( Array.isArray( this.material ) ) { - return this.rotateOnAxis( _xAxis, angle ); + const uuids = []; - } + for ( let i = 0, l = this.material.length; i < l; i ++ ) { - rotateY( angle ) { + uuids.push( serialize( meta.materials, this.material[ i ] ) ); - return this.rotateOnAxis( _yAxis, angle ); + } - } + object.material = uuids; - rotateZ( angle ) { + } else { - return this.rotateOnAxis( _zAxis, angle ); + object.material = serialize( meta.materials, this.material ); - } + } - translateOnAxis( axis, distance ) { + } - // translate object by distance along axis in object space - // axis is assumed to be normalized + // - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + if ( this.children.length > 0 ) { - this.position.add( _v1$4.multiplyScalar( distance ) ); + object.children = []; - return this; + for ( let i = 0; i < this.children.length; i ++ ) { - } + object.children.push( this.children[ i ].toJSON( meta ).object ); - translateX( distance ) { + } - return this.translateOnAxis( _xAxis, distance ); + } - } + // - translateY( distance ) { + if ( this.animations.length > 0 ) { - return this.translateOnAxis( _yAxis, distance ); + object.animations = []; - } + for ( let i = 0; i < this.animations.length; i ++ ) { - translateZ( distance ) { + const animation = this.animations[ i ]; - return this.translateOnAxis( _zAxis, distance ); + object.animations.push( serialize( meta.animations, animation ) ); - } + } - localToWorld( vector ) { + } - return vector.applyMatrix4( this.matrixWorld ); + if ( isRootObject ) { - } + const geometries = extractFromCache( meta.geometries ); + const materials = extractFromCache( meta.materials ); + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const shapes = extractFromCache( meta.shapes ); + const skeletons = extractFromCache( meta.skeletons ); + const animations = extractFromCache( meta.animations ); + const nodes = extractFromCache( meta.nodes ); - worldToLocal( vector ) { + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; + if ( skeletons.length > 0 ) output.skeletons = skeletons; + if ( animations.length > 0 ) output.animations = animations; + if ( nodes.length > 0 ) output.nodes = nodes; - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); + } - } + output.object = object; - lookAt( x, y, z ) { + return output; - // This method does not support objects having non-uniformly-scaled parent(s) + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - if ( x.isVector3 ) { + const values = []; + for ( const key in cache ) { - _target.copy( x ); + const data = cache[ key ]; + delete data.metadata; + values.push( data ); - } else { + } - _target.set( x, y, z ); + return values; } - const parent = this.parent; + } - this.updateWorldMatrix( true, false ); + clone( recursive ) { - _position$3.setFromMatrixPosition( this.matrixWorld ); + return new this.constructor().copy( this, recursive ); - if ( this.isCamera || this.isLight ) { + } - _m1$1.lookAt( _position$3, _target, this.up ); + copy( source, recursive = true ) { - } else { + this.name = source.name; - _m1$1.lookAt( _target, _position$3, this.up ); + 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.quaternion.setFromRotationMatrix( _m1$1 ); + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - if ( parent ) { + this.matrixAutoUpdate = source.matrixAutoUpdate; - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); + 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; - add( object ) { + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - if ( arguments.length > 1 ) { + this.animations = source.animations.slice(); - for ( let i = 0; i < arguments.length; i ++ ) { + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - this.add( arguments[ i ] ); + if ( recursive === true ) { - } + for ( let i = 0; i < source.children.length; i ++ ) { - return this; + const child = source.children[ i ]; + this.add( child.clone() ); + + } } - if ( object === this ) { + return this; - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; + } - } + } - if ( object && object.isObject3D ) { + Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; + Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; - if ( object.parent !== null ) { + const _v0$1 = /*@__PURE__*/ new Vector3(); + const _v1$3 = /*@__PURE__*/ new Vector3(); + const _v2$2 = /*@__PURE__*/ new Vector3(); + const _v3$1 = /*@__PURE__*/ new Vector3(); - object.parent.remove( object ); + const _vab = /*@__PURE__*/ new Vector3(); + const _vac = /*@__PURE__*/ new Vector3(); + const _vbc = /*@__PURE__*/ new Vector3(); + const _vap = /*@__PURE__*/ new Vector3(); + const _vbp = /*@__PURE__*/ new Vector3(); + const _vcp = /*@__PURE__*/ new Vector3(); + + let warnedGetUV = false; + + class Triangle { + + constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + + this.a = a; + this.b = b; + this.c = c; - } + } - object.parent = this; - this.children.push( object ); + static getNormal( a, b, c, target ) { - object.dispatchEvent( _addedEvent ); + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); - } else { + const targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); } - return this; + return target.set( 0, 0, 0 ); } - remove( object ) { + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static getBarycoord( point, a, b, c, target ) { - if ( arguments.length > 1 ) { + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$2.subVectors( point, a ); - for ( let i = 0; i < arguments.length; i ++ ) { + const dot00 = _v0$1.dot( _v0$1 ); + const dot01 = _v0$1.dot( _v1$3 ); + const dot02 = _v0$1.dot( _v2$2 ); + const dot11 = _v1$3.dot( _v1$3 ); + const dot12 = _v1$3.dot( _v2$2 ); - this.remove( arguments[ i ] ); + const denom = ( dot00 * dot11 - dot01 * dot01 ); - } + // collinear or singular triangle + if ( denom === 0 ) { - return this; + target.set( 0, 0, 0 ); + return null; } - const index = this.children.indexOf( object ); + const invDenom = 1 / denom; + const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - if ( index !== - 1 ) { + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - object.parent = null; - this.children.splice( index, 1 ); + } - object.dispatchEvent( _removedEvent ); + static containsPoint( point, a, b, c ) { + + // if the triangle is degenerate then we can't contain a point + if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) { + + return false; } - return this; + return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); } - removeFromParent() { + static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151 - const parent = this.parent; + if ( warnedGetUV === false ) { - if ( parent !== null ) { + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - parent.remove( this ); + warnedGetUV = true; } - return this; + return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target ); } - clear() { - - for ( let i = 0; i < this.children.length; i ++ ) { - - const object = this.children[ i ]; + static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { - object.parent = null; + if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) { - object.dispatchEvent( _removedEvent ); + target.x = 0; + target.y = 0; + if ( 'z' in target ) target.z = 0; + if ( 'w' in target ) target.w = 0; + return null; } - this.children.length = 0; - - return this; + target.setScalar( 0 ); + target.addScaledVector( v1, _v3$1.x ); + target.addScaledVector( v2, _v3$1.y ); + target.addScaledVector( v3, _v3$1.z ); + return target; } - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) + static isFrontFacing( a, b, c, direction ) { - this.updateWorldMatrix( true, false ); + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); - _m1$1.copy( this.matrixWorld ).invert(); + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - if ( object.parent !== null ) { + } - object.parent.updateWorldMatrix( true, false ); + set( a, b, c ) { - _m1$1.multiply( object.parent.matrixWorld ); + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - } + return this; - object.applyMatrix4( _m1$1 ); + } - this.add( object ); + setFromPointsAndIndices( points, i0, i1, i2 ) { - object.updateWorldMatrix( false, true ); + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); return this; } - getObjectById( id ) { + setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - return this.getObjectByProperty( 'id', id ); + this.a.fromBufferAttribute( attribute, i0 ); + this.b.fromBufferAttribute( attribute, i1 ); + this.c.fromBufferAttribute( attribute, i2 ); + + return this; } - getObjectByName( name ) { + clone() { - return this.getObjectByProperty( 'name', name ); + return new this.constructor().copy( this ); } - getObjectByProperty( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( let i = 0, l = this.children.length; i < l; i ++ ) { + copy( triangle ) { - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - if ( object !== undefined ) { + return this; - return object; + } - } + getArea() { - } + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); - return undefined; + return _v0$1.cross( _v1$3 ).length() * 0.5; } - getWorldPosition( target ) { - - this.updateWorldMatrix( true, false ); + getMidpoint( target ) { - return target.setFromMatrixPosition( this.matrixWorld ); + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); } - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, target, _scale$2 ); + getNormal( target ) { - return target; + return Triangle.getNormal( this.a, this.b, this.c, target ); } - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + getPlane( target ) { - return target; + return target.setFromCoplanarPoints( this.a, this.b, this.c ); } - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; + getBarycoord( point, target ) { - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); } - raycast( /* raycaster, intersects */ ) {} - - traverse( callback ) { - - callback( this ); + getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151 - const children = this.children; + if ( warnedGetUV === false ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - children[ i ].traverse( callback ); + warnedGetUV = true; } - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - const children = this.children; + return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - children[ i ].traverseVisible( callback ); + getInterpolation( point, v1, v2, v3, target ) { - } + return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); } - traverseAncestors( callback ) { - - const parent = this.parent; + containsPoint( point ) { - if ( parent !== null ) { + return Triangle.containsPoint( point, this.a, this.b, this.c ); - callback( parent ); + } - parent.traverseAncestors( callback ); + isFrontFacing( direction ) { - } + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); } - updateMatrix() { - - this.matrix.compose( this.position, this.quaternion, this.scale ); + intersectsBox( box ) { - this.matrixWorldNeedsUpdate = true; + return box.intersectsTriangle( this ); } - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { + closestPointToPoint( p, target ) { - if ( this.parent === null ) { + const a = this.a, b = this.b, c = this.c; + let v, w; - this.matrixWorld.copy( this.matrix ); + // algorithm thanks to Real-Time Collision Detection by Christer Ericson, + // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., + // under the accompanying license; see chapter 5.1.5 for detailed explanation. + // basically, we're distinguishing which of the voronoi regions of the triangle + // the point lies in with the minimum amount of redundant computation. - } else { + _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 ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); - } + } - this.matrixWorldNeedsUpdate = false; + _vbp.subVectors( p, b ); + const d3 = _vab.dot( _vbp ); + const d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { - force = true; + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); } - // update children - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + const vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - const child = children[ i ]; + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( _vab, v ); - if ( child.matrixWorldAutoUpdate === true || force === true ) { + } - child.updateMatrixWorld( force ); + _vcp.subVectors( p, c ); + const d5 = _vab.dot( _vcp ); + const d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - } + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); } - } + const vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - updateWorldMatrix( updateParents, updateChildren ) { + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); - const parent = this.parent; + } - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { + const va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - parent.updateWorldMatrix( true, false ); + _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 } - if ( this.matrixAutoUpdate ) this.updateMatrix(); + // face region + const denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; - if ( this.parent === null ) { + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - this.matrixWorld.copy( this.matrix ); + } - } else { + equals( triangle ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - } + } - // update children + } - if ( updateChildren === true ) { + const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - const children = this.children; + const _hslA = { h: 0, s: 0, l: 0 }; + const _hslB = { h: 0, s: 0, l: 0 }; - for ( let i = 0, l = children.length; i < l; i ++ ) { + function hue2rgb( p, q, t ) { - const child = children[ i ]; + 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; - if ( child.matrixWorldAutoUpdate === true ) { + } - child.updateWorldMatrix( false, true ); + class Color { - } + constructor( r, g, b ) { - } + this.isColor = true; - } + this.r = 1; + this.g = 1; + this.b = 1; - } + return this.set( r, g, b ); - toJSON( meta ) { + } - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + set( r, g, b ) { - const output = {}; + if ( g === undefined && b === undefined ) { - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + // r is THREE.Color, hex or string - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; + const value = r; - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; + if ( value && value.isColor ) { - } + this.copy( value ); - // standard Object3D serialization + } else if ( typeof value === 'number' ) { - const object = {}; + this.setHex( value ); - object.uuid = this.uuid; - object.type = this.type; + } else if ( typeof value === 'string' ) { - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + this.setStyle( value ); - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); + } - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + } else { - // object specific properties + this.setRGB( r, g, b ); - if ( this.isInstancedMesh ) { + } - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); + return this; - } + } - // + setScalar( scalar ) { - function serialize( library, element ) { + this.r = scalar; + this.g = scalar; + this.b = scalar; - if ( library[ element.uuid ] === undefined ) { + return this; - library[ element.uuid ] = element.toJSON( meta ); + } - } + setHex( hex, colorSpace = SRGBColorSpace ) { - return element.uuid; + hex = Math.floor( hex ); - } + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - if ( this.isScene ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - if ( this.background ) { + return this; - if ( this.background.isColor ) { + } - object.background = this.background.toJSON(); + setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { - } else if ( this.background.isTexture ) { + this.r = r; + this.g = g; + this.b = b; - object.background = this.background.toJSON( meta ).uuid; + ColorManagement.toWorkingColorSpace( this, colorSpace ); - } + return this; - } + } - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { + setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { - object.environment = this.environment.toJSON( meta ).uuid; + // h,s,l ranges are in 0.0 - 1.0 + h = euclideanModulo( h, 1 ); + s = clamp( s, 0, 1 ); + l = clamp( l, 0, 1 ); - } + if ( s === 0 ) { - } else if ( this.isMesh || this.isLine || this.isPoints ) { + this.r = this.g = this.b = l; - object.geometry = serialize( meta.geometries, this.geometry ); + } else { - const parameters = this.geometry.parameters; + const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + const q = ( 2 * l ) - p; - if ( parameters !== undefined && parameters.shapes !== undefined ) { + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - const shapes = parameters.shapes; + } - if ( Array.isArray( shapes ) ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + return this; - const shape = shapes[ i ]; + } - serialize( meta.shapes, shape ); + setStyle( style, colorSpace = SRGBColorSpace ) { - } + function handleAlpha( string ) { - } else { + if ( string === undefined ) return; - serialize( meta.shapes, shapes ); + if ( parseFloat( string ) < 1 ) { - } + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); } } - if ( this.isSkinnedMesh ) { - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); + let m; - if ( this.skeleton !== undefined ) { + if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { - serialize( meta.skeletons, this.skeleton ); + // rgb / hsl - object.skeleton = this.skeleton.uuid; + let color; + const name = m[ 1 ]; + const components = m[ 2 ]; - } + switch ( name ) { - } + case 'rgb': + case 'rgba': - if ( this.material !== undefined ) { + if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - if ( Array.isArray( this.material ) ) { + // rgb(255,0,0) rgba(255,0,0,0.5) - const uuids = []; + handleAlpha( color[ 4 ] ); - for ( let i = 0, l = this.material.length; i < l; i ++ ) { + 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 + ); - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + } - } + if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - object.material = uuids; + // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - } else { + handleAlpha( color[ 4 ] ); - object.material = serialize( meta.materials, this.material ); + 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 + ); - if ( this.children.length > 0 ) { + } - object.children = []; + break; - for ( let i = 0; i < this.children.length; i ++ ) { + default: - object.children.push( this.children[ i ].toJSON( meta ).object ); + console.warn( 'THREE.Color: Unknown color model ' + style ); } - } + } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - // + // hex color - if ( this.animations.length > 0 ) { + const hex = m[ 1 ]; + const size = hex.length; - object.animations = []; + if ( size === 3 ) { - for ( let i = 0; i < this.animations.length; i ++ ) { + // #ff0 + return this.setRGB( + parseInt( hex.charAt( 0 ), 16 ) / 15, + parseInt( hex.charAt( 1 ), 16 ) / 15, + parseInt( hex.charAt( 2 ), 16 ) / 15, + colorSpace + ); - const animation = this.animations[ i ]; + } else if ( size === 6 ) { - object.animations.push( serialize( meta.animations, animation ) ); + // #ff0000 + return this.setHex( parseInt( hex, 16 ), colorSpace ); - } + } else { - } + console.warn( 'THREE.Color: Invalid hex color ' + style ); - if ( isRootObject ) { + } - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); + } else if ( style && style.length > 0 ) { - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; + return this.setColorName( style, colorSpace ); } - output.object = object; + return this; - return output; + } - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { + setColorName( style, colorSpace = SRGBColorSpace ) { - const values = []; - for ( const key in cache ) { + // color keywords + const hex = _colorKeywords[ style.toLowerCase() ]; - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + if ( hex !== undefined ) { - } + // red + this.setHex( hex, colorSpace ); - return values; + } else { + + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); } + return this; + } - clone( recursive ) { + clone() { - return new this.constructor().copy( this, recursive ); + return new this.constructor( this.r, this.g, this.b ); } - copy( source, recursive = true ) { - - this.name = source.name; - - this.up.copy( source.up ); + copy( color ) { - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); + this.r = color.r; + this.g = color.g; + this.b = color.b; - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); + return this; - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + } - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + copySRGBToLinear( color ) { - this.layers.mask = source.layers.mask; - this.visible = source.visible; + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + return this; - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + } - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + copyLinearToSRGB( color ) { - if ( recursive === true ) { + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); - for ( let i = 0; i < source.children.length; i ++ ) { + return this; - const child = source.children[ i ]; - this.add( child.clone() ); + } - } + convertSRGBToLinear() { - } + this.copySRGBToLinear( this ); return this; } - } + convertLinearToSRGB() { - Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; - Object3D.DefaultMatrixWorldAutoUpdate = true; + this.copyLinearToSRGB( this ); - const _v0$1 = /*@__PURE__*/ new Vector3(); - const _v1$3 = /*@__PURE__*/ new Vector3(); - const _v2$2 = /*@__PURE__*/ new Vector3(); - const _v3$1 = /*@__PURE__*/ new Vector3(); + return this; - const _vab = /*@__PURE__*/ new Vector3(); - const _vac = /*@__PURE__*/ new Vector3(); - const _vbc = /*@__PURE__*/ new Vector3(); - const _vap = /*@__PURE__*/ new Vector3(); - const _vbp = /*@__PURE__*/ new Vector3(); - const _vcp = /*@__PURE__*/ new Vector3(); + } - class Triangle { + getHex( colorSpace = SRGBColorSpace ) { - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - this.a = a; - this.b = b; - this.c = c; + return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); } - static getNormal( a, b, c, target ) { + getHexString( colorSpace = SRGBColorSpace ) { - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); + return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { + } - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { - } + // h,s,l ranges are in 0.0 - 1.0 - return target.set( 0, 0, 0 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - } + const r = _color.r, g = _color.g, b = _color.b; - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { + const max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); + let hue, saturation; + const lightness = ( min + max ) / 2.0; - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); + if ( min === max ) { - const denom = ( dot00 * dot11 - dot01 * dot01 ); + hue = 0; + saturation = 0; - // collinear or singular triangle - if ( denom === 0 ) { + } else { - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return target.set( - 2, - 1, - 1 ); + const delta = max - min; - } + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + switch ( max ) { - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; - } + } - static containsPoint( point, a, b, c ) { + hue /= 6; + + } - this.getBarycoord( point, a, b, c, _v3$1 ); + target.h = hue; + target.s = saturation; + target.l = lightness; - return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); + return target; } - static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { + getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { - this.getBarycoord( point, p1, p2, p3, _v3$1 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - target.set( 0, 0 ); - target.addScaledVector( uv1, _v3$1.x ); - target.addScaledVector( uv2, _v3$1.y ); - target.addScaledVector( uv3, _v3$1.z ); + target.r = _color.r; + target.g = _color.g; + target.b = _color.b; return target; } - static isFrontFacing( a, b, c, direction ) { + getStyle( colorSpace = SRGBColorSpace ) { - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; + const r = _color.r, g = _color.g, b = _color.b; - } + if ( colorSpace !== SRGBColorSpace ) { - set( a, b, c ) { + // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). + return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + } - return this; + return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; } - setFromPointsAndIndices( points, i0, i1, i2 ) { + offsetHSL( h, s, l ) { - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + this.getHSL( _hslA ); - return this; + return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); } - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { + add( color ) { - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); + this.r += color.r; + this.g += color.g; + this.b += color.b; return this; } - clone() { - - return new this.constructor().copy( this ); - - } - - copy( triangle ) { + addColors( color1, color2 ) { - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; return this; } - getArea() { + addScalar( s ) { - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); + this.r += s; + this.g += s; + this.b += s; - return _v0$1.cross( _v1$3 ).length() * 0.5; + return this; } - getMidpoint( target ) { + sub( color ) { - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); + + return this; } - getNormal( target ) { + multiply( color ) { - return Triangle.getNormal( this.a, this.b, this.c, target ); + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; } - getPlane( target ) { + multiplyScalar( s ) { - return target.setFromCoplanarPoints( this.a, this.b, this.c ); + this.r *= s; + this.g *= s; + this.b *= s; + + return this; } - getBarycoord( point, target ) { + lerp( color, alpha ) { - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; } - getUV( point, uv1, uv2, uv3, target ) { + lerpColors( color1, color2, alpha ) { + + this.r = color1.r + ( color2.r - color1.r ) * alpha; + this.g = color1.g + ( color2.g - color1.g ) * alpha; + this.b = color1.b + ( color2.b - color1.b ) * alpha; - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); + return this; } - containsPoint( point ) { + lerpHSL( color, alpha ) { - return Triangle.containsPoint( point, this.a, this.b, this.c ); + 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 ); - isFrontFacing( direction ) { + this.setHSL( h, s, l ); - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); + return this; } - intersectsBox( box ) { + setFromVector3( v ) { - return box.intersectsTriangle( this ); + this.r = v.x; + this.g = v.y; + this.b = v.z; - } + return this; - closestPointToPoint( p, target ) { + } - const a = this.a, b = this.b, c = this.c; - let v, w; + applyMatrix3( m ) { - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. + const r = this.r, g = this.g, b = this.b; + const e = m.elements; - _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 ) { + 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; - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); + return this; - } + } - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { + equals( c ) { - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - } + } - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + fromArray( array, offset = 0 ) { - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; - } + return this; - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { + } - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); + toArray( array = [], offset = 0 ) { - } + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + return array; - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); + } - } + fromBufferAttribute( attribute, index ) { - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); - _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 + return this; - } + } - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; + toJSON() { - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); + return this.getHex(); } - equals( triangle ) { + *[ Symbol.iterator ]() { - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + yield this.r; + yield this.g; + yield this.b; } } - let materialId = 0; + const _color = /*@__PURE__*/ new Color(); + + Color.NAMES = _colorKeywords; + + let _materialId = 0; class Material extends EventDispatcher { @@ -8320,7 +8940,7 @@ this.isMaterial = true; - Object.defineProperty( this, 'id', { value: materialId ++ } ); + Object.defineProperty( this, 'id', { value: _materialId ++ } ); this.uuid = generateUUID(); @@ -8333,6 +8953,7 @@ this.opacity = 1; this.transparent = false; + this.alphaHash = false; this.blendSrc = SrcAlphaFactor; this.blendDst = OneMinusSrcAlphaFactor; @@ -8340,6 +8961,8 @@ 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; @@ -8372,6 +8995,7 @@ this.alphaToCoverage = false; this.premultipliedAlpha = false; + this.forceSinglePass = false; this.visible = true; @@ -8425,7 +9049,7 @@ if ( newValue === undefined ) { - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); continue; } @@ -8434,7 +9058,7 @@ if ( currentValue === undefined ) { - console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); + console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); continue; } @@ -8472,7 +9096,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'Material', generator: 'Material.toJSON' } @@ -8537,6 +9161,15 @@ } + if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; + if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; + + if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { + + data.anisotropyMap = this.anisotropyMap.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; @@ -8617,24 +9250,33 @@ if ( this.blending !== NormalBlending ) data.blending = this.blending; if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors ) data.vertexColors = true; + if ( this.vertexColors === true ) data.vertexColors = true; if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; - - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - data.colorWrite = this.colorWrite; - - data.stencilWrite = this.stencilWrite; - data.stencilWriteMask = this.stencilWriteMask; - data.stencilFunc = this.stencilFunc; - data.stencilRef = this.stencilRef; - data.stencilFuncMask = this.stencilFuncMask; - data.stencilFail = this.stencilFail; - data.stencilZFail = this.stencilZFail; - data.stencilZPass = this.stencilZPass; + if ( this.transparent === true ) data.transparent = true; + + if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; + if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; + if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; + if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; + if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; + if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; + if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); + if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; + + if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; + if ( this.depthTest === false ) data.depthTest = this.depthTest; + if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; + if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; + + if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; + if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; + if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; + if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; + if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; + if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; + if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; + if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; // rotation (SpriteMaterial) if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; @@ -8651,15 +9293,17 @@ if ( this.dithering === true ) data.dithering = true; if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + if ( this.alphaHash === true ) data.alphaHash = true; + if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; + if ( this.forceSinglePass === true ) data.forceSinglePass = true; - if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframe === true ) data.wireframe = true; if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - if ( this.flatShading === true ) data.flatShading = this.flatShading; + if ( this.flatShading === true ) data.flatShading = true; if ( this.visible === false ) data.visible = false; @@ -8667,7 +9311,7 @@ if ( this.fog === false ) data.fog = false; - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; // TODO: Copied from Object3D.toJSON @@ -8724,6 +9368,8 @@ 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; @@ -8771,8 +9417,10 @@ 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; @@ -8879,7 +9527,7 @@ class BufferAttribute { - constructor( array, itemSize, normalized ) { + constructor( array, itemSize, normalized = false ) { if ( Array.isArray( array ) ) { @@ -8894,10 +9542,12 @@ this.array = array; this.itemSize = itemSize; this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + this.normalized = normalized; this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; + this._updateRange = { offset: 0, count: - 1 }; + this.updateRanges = []; + this.gpuType = FloatType; this.version = 0; @@ -8911,6 +9561,13 @@ } + get updateRange() { + + console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 + return this._updateRange; + + } + setUsage( value ) { this.usage = value; @@ -8919,6 +9576,18 @@ } + addUpdateRange( start, count ) { + + this.updateRanges.push( { start, count } ); + + } + + clearUpdateRanges() { + + this.updateRanges.length = 0; + + } + copy( source ) { this.name = source.name; @@ -8928,6 +9597,7 @@ this.normalized = source.normalized; this.usage = source.usage; + this.gpuType = source.gpuType; return this; @@ -9043,6 +9713,26 @@ } + getComponent( index, component ) { + + let value = this.array[ index * this.itemSize + component ]; + + if ( this.normalized ) value = denormalize( value, this.array ); + + return value; + + } + + setComponent( index, component, value ) { + + if ( this.normalized ) value = normalize( value, this.array ); + + this.array[ index * this.itemSize + component ] = value; + + return this; + + } + getX( index ) { let x = this.array[ index * this.itemSize ]; @@ -9208,38 +9898,11 @@ if ( this.name !== '' ) data.name = this.name; if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; return data; } - // @deprecated - - copyColorsArray() { - - console.error( 'THREE.BufferAttribute: copyColorsArray() was removed in r144.' ); - - } - - copyVector2sArray() { - - console.error( 'THREE.BufferAttribute: copyVector2sArray() was removed in r144.' ); - - } - - copyVector3sArray() { - - console.error( 'THREE.BufferAttribute: copyVector3sArray() was removed in r144.' ); - - } - - copyVector4sArray() { - - console.error( 'THREE.BufferAttribute: copyVector4sArray() was removed in r144.' ); - - } - } class Uint16BufferAttribute extends BufferAttribute { @@ -9273,12 +9936,12 @@ } - let _id$1 = 0; + let _id$2 = 0; const _m1 = /*@__PURE__*/ new Matrix4(); const _obj = /*@__PURE__*/ new Object3D(); const _offset = /*@__PURE__*/ new Vector3(); - const _box$1 = /*@__PURE__*/ new Box3(); + const _box$2 = /*@__PURE__*/ new Box3(); const _boxMorphTargets = /*@__PURE__*/ new Box3(); const _vector$8 = /*@__PURE__*/ new Vector3(); @@ -9290,7 +9953,7 @@ this.isBufferGeometry = true; - Object.defineProperty( this, 'id', { value: _id$1 ++ } ); + Object.defineProperty( this, 'id', { value: _id$2 ++ } ); this.uuid = generateUUID(); @@ -9585,20 +10248,20 @@ for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { const morphAttribute = morphAttributesPosition[ i ]; - _box$1.setFromBufferAttribute( morphAttribute ); + _box$2.setFromBufferAttribute( morphAttribute ); if ( this.morphTargetsRelative ) { - _vector$8.addVectors( this.boundingBox.min, _box$1.min ); + _vector$8.addVectors( this.boundingBox.min, _box$2.min ); this.boundingBox.expandByPoint( _vector$8 ); - _vector$8.addVectors( this.boundingBox.max, _box$1.max ); + _vector$8.addVectors( this.boundingBox.max, _box$2.max ); this.boundingBox.expandByPoint( _vector$8 ); } else { - this.boundingBox.expandByPoint( _box$1.min ); - this.boundingBox.expandByPoint( _box$1.max ); + this.boundingBox.expandByPoint( _box$2.min ); + this.boundingBox.expandByPoint( _box$2.max ); } @@ -9647,7 +10310,7 @@ const center = this.boundingSphere.center; - _box$1.setFromBufferAttribute( position ); + _box$2.setFromBufferAttribute( position ); // process morph attributes if present @@ -9660,16 +10323,16 @@ if ( this.morphTargetsRelative ) { - _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); + _box$2.expandByPoint( _vector$8 ); - _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); + _box$2.expandByPoint( _vector$8 ); } else { - _box$1.expandByPoint( _boxMorphTargets.min ); - _box$1.expandByPoint( _boxMorphTargets.max ); + _box$2.expandByPoint( _boxMorphTargets.min ); + _box$2.expandByPoint( _boxMorphTargets.max ); } @@ -9677,7 +10340,7 @@ } - _box$1.getCenter( center ); + _box$2.getCenter( center ); // second, try to find a boundingSphere with a radius smaller than the // boundingSphere of the boundingBox: sqrt(3) smaller in the best case @@ -9989,15 +10652,6 @@ } - // @deprecated since r144 - - merge() { - - console.error( 'THREE.BufferGeometry.merge() has been removed. Use THREE.BufferGeometryUtils.mergeBufferGeometries() instead.' ); - return this; - - } - normalizeNormals() { const normals = this.attributes.normal; @@ -10120,7 +10774,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'BufferGeometry', generator: 'BufferGeometry.toJSON' } @@ -10231,7 +10885,7 @@ clone() { - return new this.constructor().copy( this ); + return new this.constructor().copy( this ); } @@ -10336,10 +10990,6 @@ this.userData = source.userData; - // geometry generator parameters - - if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters ); - return this; } @@ -10352,26 +11002,26 @@ } - const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); - const _ray$2 = /*@__PURE__*/ new Ray(); - const _sphere$3 = /*@__PURE__*/ new Sphere(); + const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); + const _ray$3 = /*@__PURE__*/ new Ray(); + const _sphere$6 = /*@__PURE__*/ new Sphere(); + const _sphereHitAt = /*@__PURE__*/ new Vector3(); const _vA$1 = /*@__PURE__*/ new Vector3(); const _vB$1 = /*@__PURE__*/ new Vector3(); const _vC$1 = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); - const _tempB = /*@__PURE__*/ new Vector3(); - const _tempC = /*@__PURE__*/ new Vector3(); - const _morphA = /*@__PURE__*/ new Vector3(); - const _morphB = /*@__PURE__*/ new Vector3(); - const _morphC = /*@__PURE__*/ new Vector3(); const _uvA$1 = /*@__PURE__*/ new Vector2(); const _uvB$1 = /*@__PURE__*/ new Vector2(); const _uvC$1 = /*@__PURE__*/ new Vector2(); + const _normalA = /*@__PURE__*/ new Vector3(); + const _normalB = /*@__PURE__*/ new Vector3(); + const _normalC = /*@__PURE__*/ new Vector3(); + const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); @@ -10402,48 +11052,92 @@ } - if ( source.morphTargetDictionary !== undefined ) { - - this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + if ( source.morphTargetDictionary !== undefined ) { + + this.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary ); + + } + + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; + this.geometry = source.geometry; + + return this; + + } + + updateMorphTargets() { + + const geometry = this.geometry; + + const morphAttributes = geometry.morphAttributes; + const keys = Object.keys( morphAttributes ); + + if ( keys.length > 0 ) { + + const morphAttribute = morphAttributes[ keys[ 0 ] ]; + + if ( morphAttribute !== undefined ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + + const name = morphAttribute[ m ].name || String( m ); + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; + + } + + } + + } + + } - } + getVertexPosition( index, target ) { - this.material = source.material; - this.geometry = source.geometry; + const geometry = this.geometry; + const position = geometry.attributes.position; + const morphPosition = geometry.morphAttributes.position; + const morphTargetsRelative = geometry.morphTargetsRelative; - return this; + target.fromBufferAttribute( position, index ); - } + const morphInfluences = this.morphTargetInfluences; - updateMorphTargets() { + if ( morphPosition && morphInfluences ) { - const geometry = this.geometry; + _morphA.set( 0, 0, 0 ); - const morphAttributes = geometry.morphAttributes; - const keys = Object.keys( morphAttributes ); + for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - if ( keys.length > 0 ) { + const influence = morphInfluences[ i ]; + const morphAttribute = morphPosition[ i ]; - const morphAttribute = morphAttributes[ keys[ 0 ] ]; + if ( influence === 0 ) continue; - if ( morphAttribute !== undefined ) { + _tempA.fromBufferAttribute( morphAttribute, index ); - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + if ( morphTargetsRelative ) { - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + _morphA.addScaledVector( _tempA, influence ); - const name = morphAttribute[ m ].name || String( m ); + } else { - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + _morphA.addScaledVector( _tempA.sub( target ), influence ); } } + target.add( _morphA ); + } + return target; + } raycast( raycaster, intersects ) { @@ -10454,36 +11148,56 @@ if ( material === undefined ) return; - // Checking boundingSphere distance to ray + // test with bounding sphere in world space if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _sphere$3.copy( geometry.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); + _sphere$6.copy( geometry.boundingSphere ); + _sphere$6.applyMatrix4( matrixWorld ); - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; + // check distance from ray origin to bounding sphere - // + _ray$3.copy( raycaster.ray ).recast( raycaster.near ); + + if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { + + if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; - // Check boundingBox before continuing + } + + // convert ray to local space of mesh + + _inverseMatrix$3.copy( matrixWorld ).invert(); + _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); + + // test with bounding box in local space if ( geometry.boundingBox !== null ) { - if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; + if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; } + // test for intersections with geometry + + this._computeIntersections( raycaster, intersects, _ray$3 ); + + } + + _computeIntersections( raycaster, intersects, rayLocalSpace ) { + let intersection; + const geometry = this.geometry; + const material = this.material; + const index = geometry.index; const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; const uv = geometry.attributes.uv; - const uv2 = geometry.attributes.uv2; + const uv1 = geometry.attributes.uv1; + const normal = geometry.attributes.normal; const groups = geometry.groups; const drawRange = geometry.drawRange; @@ -10507,7 +11221,7 @@ const b = index.getX( j + 1 ); const c = index.getX( j + 2 ); - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10532,7 +11246,7 @@ const b = index.getX( i + 1 ); const c = index.getX( i + 2 ); - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10565,7 +11279,7 @@ const b = j + 1; const c = j + 2; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10590,7 +11304,7 @@ const b = i + 1; const c = i + 2; - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10619,7 +11333,7 @@ } else { - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); } @@ -10640,82 +11354,50 @@ } - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - - _vA$1.fromBufferAttribute( position, a ); - _vB$1.fromBufferAttribute( position, b ); - _vC$1.fromBufferAttribute( position, c ); - - const morphInfluences = object.morphTargetInfluences; + function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { - if ( morphPosition && morphInfluences ) { + object.getVertexPosition( a, _vA$1 ); + object.getVertexPosition( b, _vB$1 ); + object.getVertexPosition( c, _vC$1 ); - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); - - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, a ); - _tempB.fromBufferAttribute( morphAttribute, b ); - _tempC.fromBufferAttribute( morphAttribute, c ); - - if ( morphTargetsRelative ) { + const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); + if ( intersection ) { - } else { + if ( uv ) { - _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); + _uvA$1.fromBufferAttribute( uv, a ); + _uvB$1.fromBufferAttribute( uv, b ); + _uvC$1.fromBufferAttribute( uv, c ); - } + intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); } - _vA$1.add( _morphA ); - _vB$1.add( _morphB ); - _vC$1.add( _morphC ); - - } - - if ( object.isSkinnedMesh ) { + if ( uv1 ) { - object.boneTransform( a, _vA$1 ); - object.boneTransform( b, _vB$1 ); - object.boneTransform( c, _vC$1 ); + _uvA$1.fromBufferAttribute( uv1, a ); + _uvB$1.fromBufferAttribute( uv1, b ); + _uvC$1.fromBufferAttribute( uv1, c ); - } - - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - - if ( intersection ) { + intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv2 = intersection.uv1; // @deprecated, r152 - if ( uv ) { + } - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); + if ( normal ) { - intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + _normalA.fromBufferAttribute( normal, a ); + _normalB.fromBufferAttribute( normal, b ); + _normalC.fromBufferAttribute( normal, c ); - } + intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); - if ( uv2 ) { + if ( intersection.normal.dot( ray.direction ) > 0 ) { - _uvA$1.fromBufferAttribute( uv2, a ); - _uvB$1.fromBufferAttribute( uv2, b ); - _uvC$1.fromBufferAttribute( uv2, c ); + intersection.normal.multiplyScalar( - 1 ); - intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + } } @@ -10894,6 +11576,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); @@ -10923,7 +11615,16 @@ property.isVector2 || property.isVector3 || property.isVector4 || property.isTexture || property.isQuaternion ) ) { - dst[ u ][ p ] = property.clone(); + if ( property.isRenderTargetTexture ) { + + console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); + dst[ u ][ p ] = null; + + } else { + + dst[ u ][ p ] = property.clone(); + + } } else if ( Array.isArray( property ) ) { @@ -10982,11 +11683,11 @@ if ( renderer.getRenderTarget() === null ) { // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 - return renderer.outputEncoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; + return renderer.outputColorSpace; } - return LinearSRGBColorSpace; + return ColorManagement.workingColorSpace; } @@ -11024,11 +11725,14 @@ this.lights = false; // set to use scene lights this.clipping = false; // set to use user-defined clipping planes + this.forceSinglePass = true; + this.extensions = { derivatives: false, // set to use derivatives fragDepth: false, // set to use fragment depth values drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD + shaderTextureLOD: false, // set to use shader texture LOD + clipCullDistance: false // set to use vertex shader clipping }; // When rendered geometry doesn't include these attributes but the material does, @@ -11036,7 +11740,7 @@ this.defaultAttributeValues = { 'color': [ 1, 1, 1 ], 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] + 'uv1': [ 0, 0 ] }; this.index0AttributeName = undefined; @@ -11157,6 +11861,9 @@ data.vertexShader = this.vertexShader; data.fragmentShader = this.fragmentShader; + data.lights = this.lights; + data.clipping = this.clipping; + const extensions = {}; for ( const key in this.extensions ) { @@ -11188,6 +11895,8 @@ this.projectionMatrix = new Matrix4(); this.projectionMatrixInverse = new Matrix4(); + this.coordinateSystem = WebGLCoordinateSystem; + } copy( source, recursive ) { @@ -11199,17 +11908,15 @@ this.projectionMatrix.copy( source.projectionMatrix ); this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + this.coordinateSystem = source.coordinateSystem; + return this; } getWorldDirection( target ) { - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); + return super.getWorldDirection( target ).negate(); } @@ -11436,7 +12143,7 @@ const skew = this.filmOffset; if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -11478,88 +12185,154 @@ this.type = 'CubeCamera'; this.renderTarget = renderTarget; + this.coordinateSystem = null; + this.activeMipmapLevel = 0; const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); cameraPX.layers = this.layers; - cameraPX.up.set( 0, 1, 0 ); - cameraPX.lookAt( 1, 0, 0 ); this.add( cameraPX ); const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); cameraNX.layers = this.layers; - cameraNX.up.set( 0, 1, 0 ); - cameraNX.lookAt( - 1, 0, 0 ); this.add( cameraNX ); const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); cameraPY.layers = this.layers; - cameraPY.up.set( 0, 0, - 1 ); - cameraPY.lookAt( 0, 1, 0 ); this.add( cameraPY ); const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); cameraNY.layers = this.layers; - cameraNY.up.set( 0, 0, 1 ); - cameraNY.lookAt( 0, - 1, 0 ); this.add( cameraNY ); const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); cameraPZ.layers = this.layers; - cameraPZ.up.set( 0, 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); this.add( cameraPZ ); const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); cameraNZ.layers = this.layers; - cameraNZ.up.set( 0, 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); this.add( cameraNZ ); } + updateCoordinateSystem() { + + const coordinateSystem = this.coordinateSystem; + + const cameras = this.children.concat(); + + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; + + for ( const camera of cameras ) this.remove( camera ); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + 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 if ( coordinateSystem === WebGPUCoordinateSystem ) { + + 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 { + + throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); + + } + + for ( const camera of cameras ) { + + this.add( camera ); + + camera.updateMatrixWorld(); + + } + + } + update( renderer, scene ) { if ( this.parent === null ) this.updateMatrixWorld(); - const renderTarget = this.renderTarget; + const { renderTarget, activeMipmapLevel } = this; + + if ( this.coordinateSystem !== renderer.coordinateSystem ) { + + this.coordinateSystem = renderer.coordinateSystem; + + this.updateCoordinateSystem(); + + } const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; const currentRenderTarget = renderer.getRenderTarget(); + const currentActiveCubeFace = renderer.getActiveCubeFace(); + const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); - const currentToneMapping = renderer.toneMapping; const currentXrEnabled = renderer.xr.enabled; - renderer.toneMapping = NoToneMapping; renderer.xr.enabled = false; const generateMipmaps = renderTarget.texture.generateMipmaps; renderTarget.texture.generateMipmaps = false; - renderer.setRenderTarget( renderTarget, 0 ); + renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); renderer.render( scene, cameraPX ); - renderer.setRenderTarget( renderTarget, 1 ); + renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); renderer.render( scene, cameraNX ); - renderer.setRenderTarget( renderTarget, 2 ); + renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); renderer.render( scene, cameraPY ); - renderer.setRenderTarget( renderTarget, 3 ); + renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); renderer.render( scene, cameraNY ); - renderer.setRenderTarget( renderTarget, 4 ); + renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); renderer.render( scene, cameraPZ ); + // mipmaps are generated during the last call of render() + // at this point, all sides of the cube render target are defined + renderTarget.texture.generateMipmaps = generateMipmaps; - renderer.setRenderTarget( renderTarget, 5 ); + renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); renderer.render( scene, cameraNZ ); - renderer.setRenderTarget( currentRenderTarget ); + renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); - renderer.toneMapping = currentToneMapping; renderer.xr.enabled = currentXrEnabled; renderTarget.texture.needsPMREMUpdate = true; @@ -11570,12 +12343,12 @@ class CubeTexture extends Texture { - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { images = images !== undefined ? images : []; mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); this.isCubeTexture = true; @@ -11608,7 +12381,15 @@ const image = { width: size, height: size, depth: 1 }; const images = [ image, image, image, image, image, image ]; - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + if ( options.encoding !== undefined ) { + + // @deprecated, r152 + warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; + + } + + this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, @@ -11628,7 +12409,7 @@ fromEquirectangularTexture( renderer, texture ) { this.texture.type = texture.type; - this.texture.encoding = texture.encoding; + this.texture.colorSpace = texture.colorSpace; this.texture.generateMipmaps = texture.generateMipmaps; this.texture.minFilter = texture.minFilter; @@ -11833,7 +12614,7 @@ projectPoint( point, target ) { - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); + return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); } @@ -11865,7 +12646,7 @@ } - return target.copy( direction ).multiplyScalar( t ).add( line.start ); + return target.copy( line.start ).addScaledVector( direction, t ); } @@ -11934,7 +12715,7 @@ } - const _sphere$2 = /*@__PURE__*/ new Sphere(); + const _sphere$5 = /*@__PURE__*/ new Sphere(); const _vector$7 = /*@__PURE__*/ new Vector3(); class Frustum { @@ -11974,7 +12755,7 @@ } - setFromProjectionMatrix( m ) { + setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { const planes = this.planes; const me = m.elements; @@ -11988,7 +12769,20 @@ planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); + + } else { + + throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); + + } return this; @@ -11996,23 +12790,33 @@ intersectsObject( object ) { - const geometry = object.geometry; + if ( object.boundingSphere !== undefined ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + + _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); + + } else { - _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); + const geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); + + } - return this.intersectsSphere( _sphere$2 ); + return this.intersectsSphere( _sphere$5 ); } intersectsSprite( sprite ) { - _sphere$2.center.set( 0, 0, 0 ); - _sphere$2.radius = 0.7071067811865476; - _sphere$2.applyMatrix4( sprite.matrixWorld ); + _sphere$5.center.set( 0, 0, 0 ); + _sphere$5.radius = 0.7071067811865476; + _sphere$5.applyMatrix4( sprite.matrixWorld ); - return this.intersectsSphere( _sphere$2 ); + return this.intersectsSphere( _sphere$5 ); } @@ -12152,6 +12956,7 @@ const array = attribute.array; const usage = attribute.usage; + const size = array.byteLength; const buffer = gl.createBuffer(); @@ -12164,7 +12969,7 @@ if ( array instanceof Float32Array ) { - type = 5126; + type = gl.FLOAT; } else if ( array instanceof Uint16Array ) { @@ -12172,7 +12977,7 @@ if ( isWebGL2 ) { - type = 5131; + type = gl.HALF_FLOAT; } else { @@ -12182,33 +12987,33 @@ } else { - type = 5123; + type = gl.UNSIGNED_SHORT; } } else if ( array instanceof Int16Array ) { - type = 5122; + type = gl.SHORT; } else if ( array instanceof Uint32Array ) { - type = 5125; + type = gl.UNSIGNED_INT; } else if ( array instanceof Int32Array ) { - type = 5124; + type = gl.INT; } else if ( array instanceof Int8Array ) { - type = 5120; + type = gl.BYTE; } else if ( array instanceof Uint8Array ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else if ( array instanceof Uint8ClampedArray ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else { @@ -12220,7 +13025,8 @@ buffer: buffer, type: type, bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version + version: attribute.version, + size: size }; } @@ -12228,17 +13034,43 @@ function updateBuffer( buffer, attribute, bufferType ) { const array = attribute.array; - const updateRange = attribute.updateRange; + const updateRange = attribute._updateRange; // deprecated + const updateRanges = attribute.updateRanges; gl.bindBuffer( bufferType, buffer ); - if ( updateRange.count === - 1 ) { + if ( updateRange.count === - 1 && updateRanges.length === 0 ) { // Not using update ranges - gl.bufferSubData( bufferType, 0, array ); - } else { + } + + if ( updateRanges.length !== 0 ) { + + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + + const range = updateRanges[ i ]; + if ( isWebGL2 ) { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } else { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array.subarray( range.start, range.start + range.count ) ); + + } + + } + + attribute.clearUpdateRanges(); + + } + + // deprecated + if ( updateRange.count !== - 1 ) { if ( isWebGL2 ) { @@ -12317,6 +13149,12 @@ } else if ( data.version < attribute.version ) { + if ( data.size !== attribute.array.byteLength ) { + + throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); + + } + updateBuffer( data.buffer, attribute, bufferType ); data.version = attribute.version; @@ -12411,6 +13249,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); @@ -12419,7 +13267,11 @@ } - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; + var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; + + var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; + + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; @@ -12427,19 +13279,23 @@ var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; + var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - var begin_vertex = "vec3 transformed = vec3( position );"; + var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; + + var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; + + var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\n#ifdef USE_IRIDESCENCE\n\tvec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif"; + var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; - var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\t return vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat R21 = R12;\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; + var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos.xyz );\n\t\tvec3 vSigmaY = dFdy( surf_pos.xyz );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; + var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; @@ -12457,23 +13313,23 @@ var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; + var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_v0 0.339\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_v1 0.276\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_v4 0.046\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_v5 0.016\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_v6 0.0038\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; + var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; + var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; + var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; + var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - var encodings_pars_fragment = "vec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}"; + var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; @@ -12495,35 +13351,35 @@ var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; + var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; - var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; + var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; + var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; + var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vUv ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif"; + var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec3 sheenSpecular = vec3( 0.0 );\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX_Iridescence( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometry.viewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; + var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; + var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; + var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; @@ -12533,15 +13389,15 @@ var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; + var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; + var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; + var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; + var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; @@ -12553,9 +13409,9 @@ var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; + var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; - var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; + var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; @@ -12563,149 +13419,147 @@ var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; + var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; - var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; + var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; - var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; + var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; - var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; + var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; + var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; + var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; + var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; + var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; + var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; + var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - var shadowmap_vertex = "#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; + var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tuniform int boneTextureSize;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tfloat j = i * 4.0;\n\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\ty = dy * ( y + 0.5 );\n\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\treturn bone;\n\t}\n#endif"; + var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; + var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmission.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n#endif"; + var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; - var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef texture2DLodEXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; + var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; - var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; + var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; + var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; + var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; - - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; - - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$g = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; + const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; + const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; + const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; + const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; + const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; + const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; + const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; + const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; + const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; + const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; + const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$2 = "#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$2 = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; + const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; 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, @@ -12726,8 +13580,8 @@ displacementmap_vertex: displacementmap_vertex, emissivemap_fragment: emissivemap_fragment, emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_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, @@ -12777,7 +13631,7 @@ clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, clearcoat_pars_fragment: clearcoat_pars_fragment, iridescence_pars_fragment: iridescence_pars_fragment, - output_fragment: output_fragment, + opaque_fragment: opaque_fragment, packing: packing, premultiplied_alpha_fragment: premultiplied_alpha_fragment, project_vertex: project_vertex, @@ -12802,9 +13656,6 @@ uv_pars_fragment: uv_pars_fragment, uv_pars_vertex: uv_pars_vertex, uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, worldpos_vertex: worldpos_vertex, background_vert: vertex$h, @@ -12855,10 +13706,11 @@ opacity: { value: 1.0 }, map: { value: null }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - uv2Transform: { value: /*@__PURE__*/ new Matrix3() }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } }, @@ -12866,6 +13718,7 @@ specularmap: { specularMap: { value: null }, + specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -12882,26 +13735,23 @@ aomap: { aoMap: { value: null }, - aoMapIntensity: { value: 1 } + aoMapIntensity: { value: 1 }, + aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, lightmap: { lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, - - emissivemap: { - - emissiveMap: { value: null } + lightMapIntensity: { value: 1 }, + lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, bumpmap: { bumpMap: { value: null }, + bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, bumpScale: { value: 1 } }, @@ -12909,6 +13759,7 @@ normalmap: { normalMap: { value: null }, + normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } }, @@ -12916,20 +13767,30 @@ displacementmap: { displacementMap: { value: null }, + displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, displacementScale: { value: 1 }, displacementBias: { value: 0 } }, - roughnessmap: { + emissivemap: { - roughnessMap: { value: null } + emissiveMap: { value: null }, + emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, metalnessmap: { - metalnessMap: { value: null } + metalnessMap: { value: null }, + metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } + + }, + + roughnessmap: { + + roughnessMap: { value: null }, + roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -13036,6 +13897,7 @@ scale: { value: 1.0 }, map: { value: null }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaTest: { value: 0 }, uvTransform: { value: /*@__PURE__*/ new Matrix3() } @@ -13048,9 +13910,10 @@ center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, rotation: { value: 0.0 }, map: { value: null }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } } @@ -13356,33 +14219,47 @@ { clearcoat: { value: 0 }, clearcoatMap: { value: null }, + clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalMap: { value: null }, + clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, clearcoatRoughness: { value: 0 }, clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatNormalMap: { value: null }, + clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescence: { value: 0 }, iridescenceMap: { value: null }, + iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescenceIOR: { value: 1.3 }, iridescenceThicknessMinimum: { value: 100 }, iridescenceThicknessMaximum: { value: 400 }, iridescenceThicknessMap: { value: null }, + iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheen: { value: 0 }, sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, sheenColorMap: { value: null }, + sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheenRoughness: { value: 1 }, sheenRoughnessMap: { value: null }, + sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmission: { value: 0 }, transmissionMap: { value: null }, + transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, transmissionSamplerMap: { value: null }, thickness: { value: 0 }, thicknessMap: { value: null }, + thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, attenuationDistance: { value: 0 }, attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, specularColorMap: { value: null }, + specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + specularIntensity: { value: 1 }, + specularIntensityMap: { value: null }, + specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, + anisotropyMap: { value: null }, + anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, } ] ), @@ -13417,26 +14294,26 @@ } - // Ignore background in AR - // TODO: Reconsider this. + if ( background === null ) { - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); + setClear( clearColor, clearAlpha ); - if ( session && session.environmentBlendMode === 'additive' ) { + } else if ( background && background.isColor ) { - background = null; + setClear( background, 1 ); + forceClear = true; } - if ( background === null ) { + const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); - setClear( clearColor, clearAlpha ); + if ( environmentBlendMode === 'additive' ) { - } else if ( background && background.isColor ) { + state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); - setClear( background, 1 ); - forceClear = true; + } else if ( environmentBlendMode === 'alpha-blend' ) { + + state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); } @@ -13492,6 +14369,7 @@ 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.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( currentBackground !== background || currentBackgroundVersion !== background.version || @@ -13547,6 +14425,7 @@ planeMesh.material.uniforms.t2D.value = background; planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; + planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( background.matrixAutoUpdate === true ) { @@ -13618,7 +14497,7 @@ function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - const maxVertexAttributes = gl.getParameter( 34921 ); + const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); const vaoAvailable = capabilities.isWebGL2 || extension !== null; @@ -13668,7 +14547,7 @@ if ( index !== null ) { - attributes.update( index, 34963 ); + attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); } @@ -13680,7 +14559,7 @@ if ( index !== null ) { - gl.bindBuffer( 34963, attributes.get( index ).buffer ); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); } @@ -13933,9 +14812,9 @@ } - function vertexAttribPointer( index, size, type, normalized, stride, offset ) { + function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { - if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { + if ( integer === true ) { gl.vertexAttribIPointer( index, size, type, stride, offset ); @@ -13993,6 +14872,10 @@ const type = attribute.type; const bytesPerElement = attribute.bytesPerElement; + // check for integer attributes (WebGL 2 only) + + const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); + if ( geometryAttribute.isInterleavedBufferAttribute ) { const data = geometryAttribute.data; @@ -14023,7 +14906,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14033,7 +14916,8 @@ type, normalized, stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement + ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, + integer ); } @@ -14064,7 +14948,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14074,7 +14958,8 @@ type, normalized, size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement + ( size / programAttribute.locationSize ) * i * bytesPerElement, + integer ); } @@ -14282,9 +15167,39 @@ } - extension[ methodName ]( mode, start, count, primcount ); + extension[ methodName ]( mode, start, count, primcount ); + + info.update( count, mode, primcount ); + + } + + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ], counts[ i ] ); + + } + + } else { + + extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( elementCount, mode, 1 ); - info.update( count, mode, primcount ); + } } @@ -14293,6 +15208,7 @@ this.setMode = setMode; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -14324,8 +15240,8 @@ if ( precision === 'highp' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { return 'highp'; @@ -14337,8 +15253,8 @@ if ( precision === 'mediump' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { return 'mediump'; @@ -14350,8 +15266,7 @@ } - const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || - ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); + const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; const maxPrecision = getMaxPrecision( precision ); @@ -14367,21 +15282,21 @@ const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - const maxTextures = gl.getParameter( 34930 ); - const maxVertexTextures = gl.getParameter( 35660 ); - const maxTextureSize = gl.getParameter( 3379 ); - const maxCubemapSize = gl.getParameter( 34076 ); + const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); + const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - const maxAttributes = gl.getParameter( 34921 ); - const maxVertexUniforms = gl.getParameter( 36347 ); - const maxVaryings = gl.getParameter( 36348 ); - const maxFragmentUniforms = gl.getParameter( 36349 ); + const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); + const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); + const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); const vertexTextures = maxVertexTextures > 0; const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); const floatVertexTextures = vertexTextures && floatFragmentTextures; - const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; + const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; return { @@ -14433,7 +15348,7 @@ this.numPlanes = 0; this.numIntersection = 0; - this.init = function ( planes, enableLocalClipping, camera ) { + this.init = function ( planes, enableLocalClipping ) { const enabled = planes.length !== 0 || @@ -14445,7 +15360,6 @@ localClippingEnabled = enableLocalClipping; - globalState = projectPlanes( planes, camera, 0 ); numGlobalPlanes = planes.length; return enabled; @@ -14462,7 +15376,12 @@ this.endShadows = function () { renderingShadows = false; - resetGlobalState(); + + }; + + this.setGlobalState = function ( planes, camera ) { + + globalState = projectPlanes( planes, camera, 0 ); }; @@ -14599,7 +15518,7 @@ function get( texture ) { - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { + if ( texture && texture.isTexture ) { const mapping = texture.mapping; @@ -14779,7 +15698,7 @@ } - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -14820,6 +15739,8 @@ const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); const _clearColor = /*@__PURE__*/ new Color(); let _oldTarget = null; + let _oldActiveCubeFace = 0; + let _oldActiveMipmapLevel = 0; // Golden Ratio const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; @@ -14885,6 +15806,8 @@ fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); this._setSize( 256 ); @@ -14997,7 +15920,7 @@ _cleanup( outputTarget ) { - this._renderer.setRenderTarget( _oldTarget ); + this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); outputTarget.scissorTest = false; _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); @@ -15016,6 +15939,8 @@ } _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); const cubeUVRenderTarget = renderTarget || this._allocateTargets(); this._textureToCubeUV( texture, cubeUVRenderTarget ); @@ -15037,13 +15962,13 @@ generateMipmaps: false, type: HalfFloatType, format: RGBAFormat, - encoding: LinearEncoding, + colorSpace: LinearSRGBColorSpace, depthBuffer: false }; const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width ) { + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { if ( this._pingPongRenderTarget !== null ) { @@ -15861,6 +16786,7 @@ if ( capabilities.isWebGL2 ) { getExtension( 'EXT_color_buffer_float' ); + getExtension( 'WEBGL_clip_cull_distance' ); } else { @@ -15920,6 +16846,18 @@ } + for ( const name in geometry.morphAttributes ) { + + const array = geometry.morphAttributes[ name ]; + + for ( let i = 0, l = array.length; i < l; i ++ ) { + + attributes.remove( array[ i ] ); + + } + + } + geometry.removeEventListener( 'dispose', onGeometryDispose ); delete geometries[ geometry.id ]; @@ -15969,7 +16907,7 @@ for ( const name in geometryAttributes ) { - attributes.update( geometryAttributes[ name ], 34962 ); + attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); } @@ -15983,7 +16921,7 @@ for ( let i = 0, l = array.length; i < l; i ++ ) { - attributes.update( array[ i ], 34962 ); + attributes.update( array[ i ], gl.ARRAY_BUFFER ); } @@ -16014,7 +16952,7 @@ } - } else { + } else if ( geometryPosition !== undefined ) { const array = geometryPosition.array; version = geometryPosition.version; @@ -16029,6 +16967,10 @@ } + } else { + + return; + } const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); @@ -16149,12 +17091,43 @@ } + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ] / bytesPerElement, counts[ i ] ); + + } + + } else { + + extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( elementCount, mode, 1 ); + + } + + } + // this.setMode = setMode; this.setIndex = setIndex; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -16179,23 +17152,23 @@ switch ( mode ) { - case 4: + case gl.TRIANGLES: render.triangles += instanceCount * ( count / 3 ); break; - case 1: + case gl.LINES: render.lines += instanceCount * ( count / 2 ); break; - case 3: + case gl.LINE_STRIP: render.lines += instanceCount * ( count - 1 ); break; - case 2: + case gl.LINE_LOOP: render.lines += instanceCount * count; break; - case 0: + case gl.POINTS: render.points += instanceCount * count; break; @@ -16209,7 +17182,6 @@ function reset() { - render.frame ++; render.calls = 0; render.triangles = 0; render.points = 0; @@ -16255,7 +17227,7 @@ } - function update( object, geometry, material, program ) { + function update( object, geometry, program ) { const objectInfluences = object.morphTargetInfluences; @@ -16550,11 +17522,31 @@ } - attributes.update( object.instanceMatrix, 34962 ); + if ( updateMap.get( object ) !== frame ) { + + attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); + + if ( object.instanceColor !== null ) { + + attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); + + } + + updateMap.set( object, frame ); + + } + + } + + if ( object.isSkinnedMesh ) { + + const skeleton = object.skeleton; + + if ( updateMap.get( skeleton ) !== frame ) { - if ( object.instanceColor !== null ) { + skeleton.update(); - attributes.update( object.instanceColor, 34962 ); + updateMap.set( skeleton, frame ); } @@ -16591,6 +17583,60 @@ } + class DepthTexture extends Texture { + + constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + + format = format !== undefined ? format : DepthFormat; + + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + + } + + if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isDepthTexture = true; + + this.image = { width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; + + this.compareFunction = null; + + } + + + copy( source ) { + + super.copy( source ); + + this.compareFunction = source.compareFunction; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; + + return data; + + } + + } + /** * Uniforms of a program. * Those form a tree structure with a special top-level container for the root, @@ -16634,7 +17680,12 @@ * */ + const emptyTexture = /*@__PURE__*/ new Texture(); + + const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); + emptyShadowTexture.compareFunction = LessEqualCompare; + const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); @@ -17151,7 +18202,9 @@ } - textures.setTexture2D( v || emptyTexture, unit ); + const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture; + + textures.setTexture2D( v || emptyTexture2D, unit ); } @@ -17535,6 +18588,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.setValue = getSingularSetter( activeInfo.type ); // this.path = activeInfo.name; // DEBUG @@ -17550,6 +18604,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.size = activeInfo.size; this.setValue = getPureArraySetter( activeInfo.type ); @@ -17667,7 +18722,7 @@ this.seq = []; this.map = {}; - const n = gl.getProgramParameter( program, 35718 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); for ( let i = 0; i < n; ++ i ) { @@ -17742,6 +18797,9 @@ } + // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ + const COMPLETION_STATUS_KHR = 0x91B1; + let programIdCount = 0; function handleSource( string, errorLine ) { @@ -17763,17 +18821,40 @@ } - function getEncodingComponents( encoding ) { + function getEncodingComponents( colorSpace ) { + + const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); + const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); + + let gamutMapping; + + if ( workingPrimaries === encodingPrimaries ) { + + gamutMapping = ''; + + } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { + + gamutMapping = 'LinearDisplayP3ToLinearSRGB'; - switch ( encoding ) { + } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { + + gamutMapping = 'LinearSRGBToLinearDisplayP3'; + + } + + switch ( colorSpace ) { + + case LinearSRGBColorSpace: + case LinearDisplayP3ColorSpace: + return [ gamutMapping, 'LinearTransferOETF' ]; + + case SRGBColorSpace: + case DisplayP3ColorSpace: + return [ gamutMapping, 'sRGBTransferOETF' ]; - case LinearEncoding: - return [ 'Linear', '( value )' ]; - case sRGBEncoding: - return [ 'sRGB', '( value )' ]; default: - console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); - return [ 'Linear', '( value )' ]; + console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); + return [ gamutMapping, 'LinearTransferOETF' ]; } @@ -17781,7 +18862,7 @@ function getShaderErrors( gl, shader, type ) { - const status = gl.getShaderParameter( shader, 35713 ); + const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); const errors = gl.getShaderInfoLog( shader ).trim(); if ( status && errors === '' ) return ''; @@ -17803,10 +18884,10 @@ } - function getTexelEncodingFunction( functionName, encoding ) { + function getTexelEncodingFunction( functionName, colorSpace ) { - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + const components = getEncodingComponents( colorSpace ); + return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; } @@ -17832,6 +18913,10 @@ toneMappingName = 'ACESFilmic'; break; + case AgXToneMapping: + toneMappingName = 'AgX'; + break; + case CustomToneMapping: toneMappingName = 'Custom'; break; @@ -17849,7 +18934,7 @@ function generateExtensions( parameters ) { const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' @@ -17859,6 +18944,16 @@ } + function generateVertexExtensions( parameters ) { + + const chunks = [ + parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '' + ]; + + return chunks.filter( filterEmptyLine ).join( '\n' ); + + } + function generateDefines( defines ) { const chunks = []; @@ -17881,7 +18976,7 @@ const attributes = {}; - const n = gl.getProgramParameter( program, 35721 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); for ( let i = 0; i < n; i ++ ) { @@ -17889,9 +18984,9 @@ const name = info.name; let locationSize = 1; - if ( info.type === 35674 ) locationSize = 2; - if ( info.type === 35675 ) locationSize = 3; - if ( info.type === 35676 ) locationSize = 4; + if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; + if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; + if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); @@ -17950,13 +19045,30 @@ } + const shaderChunkMap = new Map( [ + [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 + [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 + [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 + ] ); + function includeReplacer( match, include ) { - const string = ShaderChunk[ include ]; + let string = ShaderChunk[ include ]; if ( string === undefined ) { - throw new Error( 'Can not resolve #include <' + include + '>' ); + const newInclude = shaderChunkMap.get( include ); + + if ( newInclude !== undefined ) { + + string = ShaderChunk[ newInclude ]; + console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); + + } else { + + throw new Error( 'Can not resolve #include <' + include + '>' ); + + } } @@ -18146,6 +19258,8 @@ const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); + const customVertexExtensions = generateVertexExtensions( parameters ); + const customDefines = generateDefines( defines ); const program = gl.createProgram(); @@ -18157,6 +19271,9 @@ prefixVertex = [ + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18170,6 +19287,10 @@ prefixFragment = [ customExtensions, + + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18186,28 +19307,33 @@ 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.instancing ? '#define USE_INSTANCING' : '', parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapModeDefine : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', @@ -18216,28 +19342,65 @@ parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', + + // + + parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', + parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', + parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', + parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', + parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', + parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', + parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', + parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', + + parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', + parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', + + parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', + parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', + parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', + + parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', + parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', + + parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', + parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', + + parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', + parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', + parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', + + parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', + parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', + + // + + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', @@ -18257,6 +19420,10 @@ parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18284,6 +19451,24 @@ 'attribute vec3 normal;', 'attribute vec2 uv;', + '#ifdef USE_UV1', + + ' attribute vec2 uv1;', + + '#endif', + + '#ifdef USE_UV2', + + ' attribute vec2 uv2;', + + '#endif', + + '#ifdef USE_UV3', + + ' attribute vec2 uv3;', + + '#endif', + '#ifdef USE_TANGENT', ' attribute vec4 tangent;', @@ -18342,12 +19527,13 @@ generatePrecision( parameters ), + '#define SHADER_TYPE ' + parameters.shaderType, '#define SHADER_NAME ' + parameters.shaderName, customDefines, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.matcap ? '#define USE_MATCAP' : '', @@ -18360,11 +19546,14 @@ envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoat ? '#define USE_CLEARCOAT' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', @@ -18376,29 +19565,32 @@ parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.alphaTest ? '#define USE_ALPHATEST' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', @@ -18412,7 +19604,11 @@ parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + + parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18428,8 +19624,8 @@ parameters.dithering ? '#define DITHERING' : '', parameters.opaque ? '#define OPAQUE' : '', - ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), + ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below + getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', @@ -18457,6 +19653,7 @@ versionString = '#version 300 es\n'; prefixVertex = [ + customVertexExtensions, 'precision mediump sampler2DArray;', '#define attribute in', '#define varying out', @@ -18464,6 +19661,7 @@ ].join( '\n' ) + '\n' + prefixVertex; prefixFragment = [ + 'precision mediump sampler2DArray;', '#define varying in', ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', @@ -18487,8 +19685,8 @@ // console.log( '*VERTEX*', vertexGlsl ); // console.log( '*FRAGMENT*', fragmentGlsl ); - const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); + const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); + const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); @@ -18508,77 +19706,94 @@ gl.linkProgram( program ); - // check for link errors - if ( renderer.debug.checkShaderErrors ) { + function onFirstUse( self ) { - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); + // check for link errors + if ( renderer.debug.checkShaderErrors ) { - let runnable = true; - let haveDiagnostics = true; + const programLog = gl.getProgramInfoLog( program ).trim(); + const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); + const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - if ( gl.getProgramParameter( program, 35714 ) === false ) { + let runnable = true; + let haveDiagnostics = true; - runnable = false; + if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); + runnable = false; - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); + if ( typeof renderer.debug.onShaderError === 'function' ) { + + renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); - } else if ( programLog !== '' ) { + } else { - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); + // default error reporting - } else if ( vertexLog === '' || fragmentLog === '' ) { + const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); + const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - haveDiagnostics = false; + console.error( + 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + + 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + + 'Program Info Log: ' + programLog + '\n' + + vertexErrors + '\n' + + fragmentErrors + ); - } + } - if ( haveDiagnostics ) { + } else if ( programLog !== '' ) { - this.diagnostics = { + console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - runnable: runnable, + } else if ( vertexLog === '' || fragmentLog === '' ) { - programLog: programLog, + haveDiagnostics = false; - vertexShader: { + } - log: vertexLog, - prefix: prefixVertex + if ( haveDiagnostics ) { - }, + self.diagnostics = { - fragmentShader: { + runnable: runnable, - log: fragmentLog, - prefix: prefixFragment + programLog: programLog, - } + vertexShader: { - }; + log: vertexLog, + prefix: prefixVertex + + }, + + fragmentShader: { + + log: fragmentLog, + prefix: prefixFragment + + } + + }; + + } } - } + // Clean up + + // Crashes in iOS9 and iOS10. #18402 + // gl.detachShader( program, glVertexShader ); + // gl.detachShader( program, glFragmentShader ); - // Clean up + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); + cachedUniforms = new WebGLUniforms( gl, program ); + cachedAttributes = fetchAttributeLocations( gl, program ); - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); + } // set up caching for uniform locations @@ -18588,7 +19803,8 @@ if ( cachedUniforms === undefined ) { - cachedUniforms = new WebGLUniforms( gl, program ); + // Populates cachedUniforms and cachedAttributes + onFirstUse( this ); } @@ -18604,7 +19820,8 @@ if ( cachedAttributes === undefined ) { - cachedAttributes = fetchAttributeLocations( gl, program ); + // Populates cachedAttributes and cachedUniforms + onFirstUse( this ); } @@ -18612,6 +19829,23 @@ }; + // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, + // flag the program as ready immediately. It may cause a stall when it's first used. + + let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); + + this.isReady = function () { + + if ( programReady === false ) { + + programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); + + } + + return programReady; + + }; + // free resource this.destroy = function () { @@ -18625,6 +19859,7 @@ // + this.type = parameters.shaderType; this.name = parameters.shaderName; this.id = programIdCount ++; this.cacheKey = cacheKey; @@ -18637,7 +19872,7 @@ } - let _id = 0; + let _id$1 = 0; class WebGLShaderCache { @@ -18751,7 +19986,7 @@ constructor( code ) { - this.id = _id ++; + this.id = _id$1 ++; this.code = code; this.usedTimes = 0; @@ -18766,9 +20001,10 @@ const _customShaders = new WebGLShaderCache(); const programs = []; - const isWebGL2 = capabilities.isWebGL2; + const IS_WEBGL2 = capabilities.isWebGL2; const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const vertexTextures = capabilities.vertexTextures; + const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; + let precision = capabilities.precision; const shaderIDs = { @@ -18789,6 +20025,14 @@ SpriteMaterial: 'sprite' }; + function getChannel( value ) { + + if ( value === 0 ) return 'uv'; + + return `uv${ value }`; + + } + function getParameters( material, lights, shadows, scene, object ) { const fog = scene.fog; @@ -18848,20 +20092,84 @@ customVertexShaderID = _customShaders.getVertexShaderID( material ); customFragmentShaderID = _customShaders.getFragmentShaderID( material ); - } + } + + const currentRenderTarget = renderer.getRenderTarget(); + + const IS_INSTANCEDMESH = object.isInstancedMesh === true; + const IS_BATCHEDMESH = object.isBatchedMesh === true; + + const HAS_MAP = !! material.map; + const HAS_MATCAP = !! material.matcap; + const HAS_ENVMAP = !! envMap; + const HAS_AOMAP = !! material.aoMap; + const HAS_LIGHTMAP = !! material.lightMap; + const HAS_BUMPMAP = !! material.bumpMap; + const HAS_NORMALMAP = !! material.normalMap; + const HAS_DISPLACEMENTMAP = !! material.displacementMap; + const HAS_EMISSIVEMAP = !! material.emissiveMap; + + const HAS_METALNESSMAP = !! material.metalnessMap; + const HAS_ROUGHNESSMAP = !! material.roughnessMap; + + const HAS_ANISOTROPY = material.anisotropy > 0; + const HAS_CLEARCOAT = material.clearcoat > 0; + const HAS_IRIDESCENCE = material.iridescence > 0; + const HAS_SHEEN = material.sheen > 0; + const HAS_TRANSMISSION = material.transmission > 0; + + const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; + + const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; + const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; + const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; + + const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; + const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; + + const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; + const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; + + const HAS_SPECULARMAP = !! material.specularMap; + const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; + const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; + + const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; + const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; + + const HAS_GRADIENTMAP = !! material.gradientMap; + + const HAS_ALPHAMAP = !! material.alphaMap; + + const HAS_ALPHATEST = material.alphaTest > 0; + + const HAS_ALPHAHASH = !! material.alphaHash; + + const HAS_EXTENSIONS = !! material.extensions; + + const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1; + const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2; + const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3; + + let toneMapping = NoToneMapping; + + if ( material.toneMapped ) { + + if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { + + toneMapping = renderer.toneMapping; - const currentRenderTarget = renderer.getRenderTarget(); + } - const useAlphaTest = material.alphaTest > 0; - const useClearcoat = material.clearcoat > 0; - const useIridescence = material.iridescence > 0; + } const parameters = { - isWebGL2: isWebGL2, + isWebGL2: IS_WEBGL2, shaderID: shaderID, - shaderName: material.type, + shaderType: material.type, + shaderName: material.name, vertexShader: vertexShader, fragmentShader: fragmentShader, @@ -18875,72 +20183,117 @@ precision: precision, - instancing: object.isInstancedMesh === true, - instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, + batching: IS_BATCHEDMESH, + instancing: IS_INSTANCEDMESH, + instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, - supportsVertexTextures: vertexTextures, - outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ), - map: !! material.map, - matcap: !! material.matcap, - envMap: !! envMap, - envMapMode: envMap && envMap.mapping, + supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, + outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), + + map: HAS_MAP, + matcap: HAS_MATCAP, + envMap: HAS_ENVMAP, + envMapMode: HAS_ENVMAP && envMap.mapping, envMapCubeUVHeight: envMapCubeUVHeight, - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, - - decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ), - - clearcoat: useClearcoat, - clearcoatMap: useClearcoat && !! material.clearcoatMap, - clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, - clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, - - iridescence: useIridescence, - iridescenceMap: useIridescence && !! material.iridescenceMap, - iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap, - - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - specularIntensityMap: !! material.specularIntensityMap, - specularColorMap: !! material.specularColorMap, + aoMap: HAS_AOMAP, + lightMap: HAS_LIGHTMAP, + bumpMap: HAS_BUMPMAP, + normalMap: HAS_NORMALMAP, + displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, + emissiveMap: HAS_EMISSIVEMAP, - opaque: material.transparent === false && material.blending === NormalBlending, + normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, + normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, + + metalnessMap: HAS_METALNESSMAP, + roughnessMap: HAS_ROUGHNESSMAP, + + anisotropy: HAS_ANISOTROPY, + anisotropyMap: HAS_ANISOTROPYMAP, - alphaMap: !! material.alphaMap, - alphaTest: useAlphaTest, + clearcoat: HAS_CLEARCOAT, + clearcoatMap: HAS_CLEARCOATMAP, + clearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP, + clearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP, - gradientMap: !! material.gradientMap, + iridescence: HAS_IRIDESCENCE, + iridescenceMap: HAS_IRIDESCENCEMAP, + iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP, - sheen: material.sheen > 0, - sheenColorMap: !! material.sheenColorMap, - sheenRoughnessMap: !! material.sheenRoughnessMap, + sheen: HAS_SHEEN, + sheenColorMap: HAS_SHEEN_COLORMAP, + sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP, - transmission: material.transmission > 0, - transmissionMap: !! material.transmissionMap, - thicknessMap: !! material.thicknessMap, + specularMap: HAS_SPECULARMAP, + specularColorMap: HAS_SPECULAR_COLORMAP, + specularIntensityMap: HAS_SPECULAR_INTENSITYMAP, + + transmission: HAS_TRANSMISSION, + transmissionMap: HAS_TRANSMISSIONMAP, + thicknessMap: HAS_THICKNESSMAP, + + gradientMap: HAS_GRADIENTMAP, + + opaque: material.transparent === false && material.blending === NormalBlending, + + alphaMap: HAS_ALPHAMAP, + alphaTest: HAS_ALPHATEST, + alphaHash: HAS_ALPHAHASH, combine: material.combine, - vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ), + // + + mapUv: HAS_MAP && getChannel( material.map.channel ), + aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), + lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), + bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), + normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), + displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), + emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), + + metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), + roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), + + anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), + + clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), + clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), + clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), + + iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), + iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), + + sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), + sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), + + specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), + specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), + specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), + + transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), + thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), + + alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), + + // + + vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), vertexColors: material.vertexColors, vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap, - uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap, + vertexUv1s: HAS_ATTRIBUTE_UV1, + vertexUv2s: HAS_ATTRIBUTE_UV2, + vertexUv3s: HAS_ATTRIBUTE_UV3, + + pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), fog: !! fog, useFog: material.fog === true, fogExp2: ( fog && fog.isFogExp2 ), - flatShading: !! material.flatShading, + flatShading: material.flatShading === true, - sizeAttenuation: material.sizeAttenuation, + sizeAttenuation: material.sizeAttenuation === true, logarithmicDepthBuffer: logarithmicDepthBuffer, skinning: object.isSkinnedMesh === true, @@ -18963,6 +20316,8 @@ numSpotLightShadows: lights.spotShadowMap.length, numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, + numLightProbes: lights.numLightProbes, + numClippingPlanes: clipping.numPlanes, numClipIntersection: clipping.numIntersection, @@ -18971,27 +20326,31 @@ shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, shadowMapType: renderer.shadowMap.type, - toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, + toneMapping: toneMapping, + useLegacyLights: renderer._useLegacyLights, + + decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), premultipliedAlpha: material.premultipliedAlpha, doubleSided: material.side === DoubleSide, flipSided: material.side === BackSide, - useDepthPacking: !! material.depthPacking, + useDepthPacking: material.depthPacking >= 0, depthPacking: material.depthPacking || 0, index0AttributeName: material.index0AttributeName, - extensionDerivatives: material.extensions && material.extensions.derivatives, - extensionFragDepth: material.extensions && material.extensions.fragDepth, - extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, - extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, + extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, + extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, + extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, + extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, + extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ), - rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), + rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), + rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), customProgramCacheKey: material.customProgramCacheKey() @@ -19031,7 +20390,7 @@ getProgramCacheKeyParameters( array, parameters ); getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputEncoding ); + array.push( renderer.outputColorSpace ); } @@ -19044,11 +20403,33 @@ function getProgramCacheKeyParameters( array, parameters ) { array.push( parameters.precision ); - array.push( parameters.outputEncoding ); + 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.vertexUvs ); array.push( parameters.fogExp2 ); array.push( parameters.sizeAttenuation ); array.push( parameters.morphTargetsCount ); @@ -19063,6 +20444,7 @@ 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 ); @@ -19083,64 +20465,38 @@ _programLayers.enable( 2 ); if ( parameters.instancingColor ) _programLayers.enable( 3 ); - if ( parameters.map ) - _programLayers.enable( 4 ); if ( parameters.matcap ) - _programLayers.enable( 5 ); + _programLayers.enable( 4 ); if ( parameters.envMap ) + _programLayers.enable( 5 ); + if ( parameters.normalMapObjectSpace ) _programLayers.enable( 6 ); - if ( parameters.lightMap ) + if ( parameters.normalMapTangentSpace ) _programLayers.enable( 7 ); - if ( parameters.aoMap ) + if ( parameters.clearcoat ) _programLayers.enable( 8 ); - if ( parameters.emissiveMap ) + if ( parameters.iridescence ) _programLayers.enable( 9 ); - if ( parameters.bumpMap ) + if ( parameters.alphaTest ) _programLayers.enable( 10 ); - if ( parameters.normalMap ) + if ( parameters.vertexColors ) _programLayers.enable( 11 ); - if ( parameters.objectSpaceNormalMap ) + if ( parameters.vertexAlphas ) _programLayers.enable( 12 ); - if ( parameters.tangentSpaceNormalMap ) + if ( parameters.vertexUv1s ) _programLayers.enable( 13 ); - if ( parameters.clearcoat ) + if ( parameters.vertexUv2s ) _programLayers.enable( 14 ); - if ( parameters.clearcoatMap ) + if ( parameters.vertexUv3s ) _programLayers.enable( 15 ); - if ( parameters.clearcoatRoughnessMap ) + if ( parameters.vertexTangents ) _programLayers.enable( 16 ); - if ( parameters.clearcoatNormalMap ) + if ( parameters.anisotropy ) _programLayers.enable( 17 ); - if ( parameters.iridescence ) + if ( parameters.alphaHash ) _programLayers.enable( 18 ); - if ( parameters.iridescenceMap ) + if ( parameters.batching ) _programLayers.enable( 19 ); - if ( parameters.iridescenceThicknessMap ) - _programLayers.enable( 20 ); - if ( parameters.displacementMap ) - _programLayers.enable( 21 ); - if ( parameters.specularMap ) - _programLayers.enable( 22 ); - if ( parameters.roughnessMap ) - _programLayers.enable( 23 ); - if ( parameters.metalnessMap ) - _programLayers.enable( 24 ); - if ( parameters.gradientMap ) - _programLayers.enable( 25 ); - if ( parameters.alphaMap ) - _programLayers.enable( 26 ); - if ( parameters.alphaTest ) - _programLayers.enable( 27 ); - if ( parameters.vertexColors ) - _programLayers.enable( 28 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 29 ); - if ( parameters.vertexUvs ) - _programLayers.enable( 30 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 31 ); - if ( parameters.uvsVertexOnly ) - _programLayers.enable( 32 ); array.push( _programLayers.mask ); _programLayers.disableAll(); @@ -19165,7 +20521,7 @@ _programLayers.enable( 8 ); if ( parameters.shadowMapEnabled ) _programLayers.enable( 9 ); - if ( parameters.physicallyCorrectLights ) + if ( parameters.useLegacyLights ) _programLayers.enable( 10 ); if ( parameters.doubleSided ) _programLayers.enable( 11 ); @@ -19175,26 +20531,16 @@ _programLayers.enable( 13 ); if ( parameters.dithering ) _programLayers.enable( 14 ); - if ( parameters.specularIntensityMap ) + if ( parameters.transmission ) _programLayers.enable( 15 ); - if ( parameters.specularColorMap ) + if ( parameters.sheen ) _programLayers.enable( 16 ); - if ( parameters.transmission ) + if ( parameters.opaque ) _programLayers.enable( 17 ); - if ( parameters.transmissionMap ) + if ( parameters.pointsUvs ) _programLayers.enable( 18 ); - if ( parameters.thicknessMap ) - _programLayers.enable( 19 ); - if ( parameters.sheen ) - _programLayers.enable( 20 ); - if ( parameters.sheenColorMap ) - _programLayers.enable( 21 ); - if ( parameters.sheenRoughnessMap ) - _programLayers.enable( 22 ); if ( parameters.decodeVideoTexture ) - _programLayers.enable( 23 ); - if ( parameters.opaque ) - _programLayers.enable( 24 ); + _programLayers.enable( 19 ); array.push( _programLayers.mask ); @@ -19741,7 +21087,9 @@ numDirectionalShadows: - 1, numPointShadows: - 1, numSpotShadows: - 1, - numSpotMaps: - 1 + numSpotMaps: - 1, + + numLightProbes: - 1 }, ambient: [ 0, 0, 0 ], @@ -19763,7 +21111,8 @@ pointShadowMap: [], pointShadowMatrix: [], hemi: [], - numSpotLightShadowsWithMaps: 0 + numSpotLightShadowsWithMaps: 0, + numLightProbes: 0 }; @@ -19773,7 +21122,7 @@ const matrix4 = new Matrix4(); const matrix42 = new Matrix4(); - function setup( lights, physicallyCorrectLights ) { + function setup( lights, useLegacyLights ) { let r = 0, g = 0, b = 0; @@ -19791,11 +21140,13 @@ let numSpotMaps = 0; let numSpotShadowsWithMaps = 0; + let numLightProbes = 0; + // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] lights.sort( shadowCastingAndTexturingLightsFirst ); // artist-friendly light intensity scaling factor - const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; for ( let i = 0, l = lights.length; i < l; i ++ ) { @@ -19821,6 +21172,8 @@ } + numLightProbes ++; + } else if ( light.isDirectionalLight ) { const uniforms = cache.get( light ); @@ -19967,8 +21320,17 @@ // WebGL 2 - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; + if ( extensions.has( 'OES_texture_float_linear' ) === true ) { + + 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; + + } } else { @@ -20008,7 +21370,8 @@ hash.numDirectionalShadows !== numDirectionalShadows || hash.numPointShadows !== numPointShadows || hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps ) { + hash.numSpotMaps !== numSpotMaps || + hash.numLightProbes !== numLightProbes ) { state.directional.length = directionalLength; state.spot.length = spotLength; @@ -20027,6 +21390,7 @@ state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; state.spotLightMap.length = numSpotMaps; state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; + state.numLightProbes = numLightProbes; hash.directionalLength = directionalLength; hash.pointLength = pointLength; @@ -20039,6 +21403,8 @@ hash.numSpotShadows = numSpotShadows; hash.numSpotMaps = numSpotMaps; + hash.numLightProbes = numLightProbes; + state.version = nextVersion ++; } @@ -20163,9 +21529,9 @@ } - function setupLights( physicallyCorrectLights ) { + function setupLights( useLegacyLights ) { - lights.setup( lightsArray, physicallyCorrectLights ); + lights.setup( lightsArray, useLegacyLights ); } @@ -20300,10 +21666,6 @@ this.type = 'MeshDistanceMaterial'; - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; - this.map = null; this.alphaMap = null; @@ -20320,10 +21682,6 @@ super.copy( source ); - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; - this.map = source.map; this.alphaMap = source.alphaMap; @@ -20358,7 +21716,7 @@ _maxTextureSize = _capabilities.maxTextureSize; - const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; const shadowMaterialVertical = new ShaderMaterial( { defines: { @@ -20397,6 +21755,7 @@ this.needsUpdate = false; this.type = PCFShadowMap; + let _previousType = this.type; this.render = function ( lights, scene, camera ) { @@ -20417,6 +21776,11 @@ _state.buffers.depth.setTest( true ); _state.setScissorTest( false ); + // check for shadow map type changes + + const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); + const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); + // render depth map for ( let i = 0, il = lights.length; i < il; i ++ ) { @@ -20461,10 +21825,16 @@ } - if ( shadow.map === null ) { + if ( shadow.map === null || toVSM === true || fromVSM === true ) { const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; + if ( shadow.map !== null ) { + + shadow.map.dispose(); + + } + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); shadow.map.texture.name = light.name + '.shadowMap'; @@ -20510,6 +21880,8 @@ } + _previousType = this.type; + scope.needsUpdate = false; _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); @@ -20556,7 +21928,7 @@ } - function getDepthMaterial( object, material, light, shadowCameraNear, shadowCameraFar, type ) { + function getDepthMaterial( object, material, light, type ) { let result = null; @@ -20570,37 +21942,38 @@ result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - } + if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || + ( material.displacementMap && material.displacementScale !== 0 ) || + ( material.alphaMap && material.alphaTest > 0 ) || + ( material.map && material.alphaTest > 0 ) ) { - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) || - ( material.map && material.alphaTest > 0 ) ) { + // in this case we need a unique material instance reflecting the + // appropriate state - // in this case we need a unique material instance reflecting the - // appropriate state + const keyA = result.uuid, keyB = material.uuid; - const keyA = result.uuid, keyB = material.uuid; + let materialsForVariant = _materialCache[ keyA ]; - let materialsForVariant = _materialCache[ keyA ]; + if ( materialsForVariant === undefined ) { - if ( materialsForVariant === undefined ) { + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + } - } + let cachedMaterial = materialsForVariant[ keyB ]; - let cachedMaterial = materialsForVariant[ keyB ]; + if ( cachedMaterial === undefined ) { - if ( cachedMaterial === undefined ) { + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; + material.addEventListener( 'dispose', onMaterialDispose ); - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + } - } + result = cachedMaterial; - result = cachedMaterial; + } } @@ -20634,9 +22007,8 @@ if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - result.referencePosition.setFromMatrixPosition( light.matrixWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + const materialProperties = _renderer.properties.get( result ); + materialProperties.light = light; } @@ -20670,20 +22042,28 @@ if ( groupMaterial && groupMaterial.visible ) { - const depthMaterial = getDepthMaterial( object, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); + } } } else if ( material.visible ) { - const depthMaterial = getDepthMaterial( object, material, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, material, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); + } } @@ -20700,6 +22080,32 @@ } + function onMaterialDispose( event ) { + + const material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + // make sure to remove the unique distance/depth materials used for shadow map rendering + + for ( const id in _materialCache ) { + + const cache = _materialCache[ id ]; + + const uuid = event.target.uuid; + + if ( uuid in cache ) { + + const shadowMaterial = cache[ uuid ]; + shadowMaterial.dispose(); + delete cache[ uuid ]; + + } + + } + + } + } function WebGLState( gl, extensions, capabilities ) { @@ -20779,11 +22185,11 @@ if ( depthTest ) { - enable( 2929 ); + enable( gl.DEPTH_TEST ); } else { - disable( 2929 ); + disable( gl.DEPTH_TEST ); } @@ -20808,47 +22214,47 @@ case NeverDepth: - gl.depthFunc( 512 ); + gl.depthFunc( gl.NEVER ); break; case AlwaysDepth: - gl.depthFunc( 519 ); + gl.depthFunc( gl.ALWAYS ); break; case LessDepth: - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); break; case LessEqualDepth: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); break; case EqualDepth: - gl.depthFunc( 514 ); + gl.depthFunc( gl.EQUAL ); break; case GreaterEqualDepth: - gl.depthFunc( 518 ); + gl.depthFunc( gl.GEQUAL ); break; case GreaterDepth: - gl.depthFunc( 516 ); + gl.depthFunc( gl.GREATER ); break; case NotEqualDepth: - gl.depthFunc( 517 ); + gl.depthFunc( gl.NOTEQUAL ); break; default: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); } @@ -20910,11 +22316,11 @@ if ( stencilTest ) { - enable( 2960 ); + enable( gl.STENCIL_TEST ); } else { - disable( 2960 ); + disable( gl.STENCIL_TEST ); } @@ -21008,7 +22414,7 @@ const stencilBuffer = new StencilBuffer(); const uboBindings = new WeakMap(); - const uboProgamMap = new WeakMap(); + const uboProgramMap = new WeakMap(); let enabledCapabilities = {}; @@ -21026,6 +22432,8 @@ let currentBlendEquationAlpha = null; let currentBlendSrcAlpha = null; let currentBlendDstAlpha = null; + let currentBlendColor = new Color( 0, 0, 0 ); + let currentBlendAlpha = 0; let currentPremultipledAlpha = false; let currentFlipSided = null; @@ -21036,11 +22444,11 @@ let currentPolygonOffsetFactor = null; let currentPolygonOffsetUnits = null; - const maxTextures = gl.getParameter( 35661 ); + const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); let lineWidthAvailable = false; let version = 0; - const glVersion = gl.getParameter( 7938 ); + const glVersion = gl.getParameter( gl.VERSION ); if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { @@ -21057,24 +22465,32 @@ let currentTextureSlot = null; let currentBoundTextures = {}; - const scissorParam = gl.getParameter( 3088 ); - const viewportParam = gl.getParameter( 2978 ); + const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); + const viewportParam = gl.getParameter( gl.VIEWPORT ); const currentScissor = new Vector4().fromArray( scissorParam ); const currentViewport = new Vector4().fromArray( viewportParam ); - function createTexture( type, target, count ) { + function createTexture( type, target, count, dimensions ) { const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. const texture = gl.createTexture(); gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); + gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); for ( let i = 0; i < count; i ++ ) { - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); + if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { + + gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } else { + + gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } } @@ -21083,8 +22499,15 @@ } const emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); + emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); + emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); + + if ( isWebGL2 ) { + + emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); + emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); + + } // init @@ -21092,12 +22515,12 @@ depthBuffer.setClear( 1 ); stencilBuffer.setClear( 0 ); - enable( 2929 ); + enable( gl.DEPTH_TEST ); depthBuffer.setFunc( LessEqualDepth ); setFlipSided( false ); setCullFace( CullFaceBack ); - enable( 2884 ); + enable( gl.CULL_FACE ); setBlending( NoBlending ); @@ -21135,17 +22558,17 @@ if ( isWebGL2 ) { - // 36009 is equivalent to 36160 + // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER - if ( target === 36009 ) { + if ( target === gl.DRAW_FRAMEBUFFER ) { - currentBoundFramebuffers[ 36160 ] = framebuffer; + currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; } - if ( target === 36160 ) { + if ( target === gl.FRAMEBUFFER ) { - currentBoundFramebuffers[ 36009 ] = framebuffer; + currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; } @@ -21180,11 +22603,11 @@ const textures = renderTarget.texture; - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { for ( let i = 0, il = textures.length; i < il; i ++ ) { - drawBuffers[ i ] = 36064 + i; + drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; } @@ -21196,9 +22619,9 @@ } else { - if ( drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - drawBuffers[ 0 ] = 36064; + drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; needsUpdate = true; @@ -21208,9 +22631,9 @@ } else { - if ( drawBuffers[ 0 ] !== 1029 ) { + if ( drawBuffers[ 0 ] !== gl.BACK ) { - drawBuffers[ 0 ] = 1029; + drawBuffers[ 0 ] = gl.BACK; needsUpdate = true; @@ -21252,15 +22675,15 @@ } const equationToGL = { - [ AddEquation ]: 32774, - [ SubtractEquation ]: 32778, - [ ReverseSubtractEquation ]: 32779 + [ AddEquation ]: gl.FUNC_ADD, + [ SubtractEquation ]: gl.FUNC_SUBTRACT, + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT }; if ( isWebGL2 ) { - equationToGL[ MinEquation ] = 32775; - equationToGL[ MaxEquation ] = 32776; + equationToGL[ MinEquation ] = gl.MIN; + equationToGL[ MaxEquation ] = gl.MAX; } else { @@ -21276,26 +22699,30 @@ } const factorToGL = { - [ ZeroFactor ]: 0, - [ OneFactor ]: 1, - [ SrcColorFactor ]: 768, - [ SrcAlphaFactor ]: 770, - [ SrcAlphaSaturateFactor ]: 776, - [ DstColorFactor ]: 774, - [ DstAlphaFactor ]: 772, - [ OneMinusSrcColorFactor ]: 769, - [ OneMinusSrcAlphaFactor ]: 771, - [ OneMinusDstColorFactor ]: 775, - [ OneMinusDstAlphaFactor ]: 773 + [ 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 }; - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { if ( blending === NoBlending ) { if ( currentBlendingEnabled === true ) { - disable( 3042 ); + disable( gl.BLEND ); currentBlendingEnabled = false; } @@ -21306,7 +22733,7 @@ if ( currentBlendingEnabled === false ) { - enable( 3042 ); + enable( gl.BLEND ); currentBlendingEnabled = true; } @@ -21317,7 +22744,7 @@ if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - gl.blendEquation( 32774 ); + gl.blendEquation( gl.FUNC_ADD ); currentBlendEquation = AddEquation; currentBlendEquationAlpha = AddEquation; @@ -21329,19 +22756,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); + gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 1, 1 ); + gl.blendFunc( gl.ONE, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); + gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); break; default: @@ -21355,19 +22782,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 770, 1 ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFunc( 0, 768 ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); break; default: @@ -21382,6 +22809,8 @@ currentBlendDst = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor.set( 0, 0, 0 ); + currentBlendAlpha = 0; currentBlending = blending; currentPremultipledAlpha = premultipliedAlpha; @@ -21418,6 +22847,15 @@ } + if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { + + gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); + + currentBlendColor.copy( blendColor ); + currentBlendAlpha = blendAlpha; + + } + currentBlending = blending; currentPremultipledAlpha = false; @@ -21426,8 +22864,8 @@ function setMaterial( material, frontFaceCW ) { material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); + ? disable( gl.CULL_FACE ) + : enable( gl.CULL_FACE ); let flipSided = ( material.side === BackSide ); if ( frontFaceCW ) flipSided = ! flipSided; @@ -21436,7 +22874,7 @@ ( material.blending === NormalBlending && material.transparent === false ) ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); depthBuffer.setFunc( material.depthFunc ); depthBuffer.setTest( material.depthTest ); @@ -21456,8 +22894,8 @@ setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); material.alphaToCoverage === true - ? enable( 32926 ) - : disable( 32926 ); + ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) + : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); } @@ -21469,11 +22907,11 @@ if ( flipSided ) { - gl.frontFace( 2304 ); + gl.frontFace( gl.CW ); } else { - gl.frontFace( 2305 ); + gl.frontFace( gl.CCW ); } @@ -21487,21 +22925,21 @@ if ( cullFace !== CullFaceNone ) { - enable( 2884 ); + enable( gl.CULL_FACE ); if ( cullFace !== currentCullFace ) { if ( cullFace === CullFaceBack ) { - gl.cullFace( 1029 ); + gl.cullFace( gl.BACK ); } else if ( cullFace === CullFaceFront ) { - gl.cullFace( 1028 ); + gl.cullFace( gl.FRONT ); } else { - gl.cullFace( 1032 ); + gl.cullFace( gl.FRONT_AND_BACK ); } @@ -21509,7 +22947,7 @@ } else { - disable( 2884 ); + disable( gl.CULL_FACE ); } @@ -21533,7 +22971,7 @@ if ( polygonOffset ) { - enable( 32823 ); + enable( gl.POLYGON_OFFSET_FILL ); if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { @@ -21546,7 +22984,7 @@ } else { - disable( 32823 ); + disable( gl.POLYGON_OFFSET_FILL ); } @@ -21556,11 +22994,11 @@ if ( scissorTest ) { - enable( 3089 ); + enable( gl.SCISSOR_TEST ); } else { - disable( 3089 ); + disable( gl.SCISSOR_TEST ); } @@ -21570,7 +23008,7 @@ function activeTexture( webglSlot ) { - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; if ( currentTextureSlot !== webglSlot ) { @@ -21587,7 +23025,7 @@ if ( currentTextureSlot === null ) { - webglSlot = 33984 + maxTextures - 1; + webglSlot = gl.TEXTURE0 + maxTextures - 1; } else { @@ -21805,13 +23243,13 @@ function updateUBOMapping( uniformsGroup, program ) { - let mapping = uboProgamMap.get( program ); + let mapping = uboProgramMap.get( program ); if ( mapping === undefined ) { mapping = new WeakMap(); - uboProgamMap.set( program, mapping ); + uboProgramMap.set( program, mapping ); } @@ -21829,16 +23267,15 @@ function uniformBlockBinding( uniformsGroup, program ) { - const mapping = uboProgamMap.get( program ); + const mapping = uboProgramMap.get( program ); const blockIndex = mapping.get( uniformsGroup ); - if ( uboBindings.get( uniformsGroup ) !== blockIndex ) { + if ( uboBindings.get( program ) !== blockIndex ) { // bind shader specific block index to global block point - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - uboBindings.set( uniformsGroup, blockIndex ); + uboBindings.set( program, blockIndex ); } @@ -21850,43 +23287,44 @@ // reset state - gl.disable( 3042 ); - gl.disable( 2884 ); - gl.disable( 2929 ); - gl.disable( 32823 ); - gl.disable( 3089 ); - gl.disable( 2960 ); - gl.disable( 32926 ); + 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( 32774 ); - gl.blendFunc( 1, 0 ); - gl.blendFuncSeparate( 1, 0, 1, 0 ); + 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.colorMask( true, true, true, true ); gl.clearColor( 0, 0, 0, 0 ); gl.depthMask( true ); - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); gl.clearDepth( 1 ); gl.stencilMask( 0xffffffff ); - gl.stencilFunc( 519, 0, 0xffffffff ); - gl.stencilOp( 7680, 7680, 7680 ); + gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); + gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); gl.clearStencil( 0 ); - gl.cullFace( 1029 ); - gl.frontFace( 2305 ); + gl.cullFace( gl.BACK ); + gl.frontFace( gl.CCW ); gl.polygonOffset( 0, 0 ); - gl.activeTexture( 33984 ); + gl.activeTexture( gl.TEXTURE0 ); - gl.bindFramebuffer( 36160, null ); + gl.bindFramebuffer( gl.FRAMEBUFFER, null ); if ( isWebGL2 === true ) { - gl.bindFramebuffer( 36009, null ); - gl.bindFramebuffer( 36008, null ); + gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); + gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); } @@ -21918,6 +23356,8 @@ currentBlendEquationAlpha = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor = new Color( 0, 0, 0 ); + currentBlendAlpha = 0; currentPremultipledAlpha = false; currentFlipSided = null; @@ -21994,10 +23434,6 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { const isWebGL2 = capabilities.isWebGL2; - const maxTextures = capabilities.maxTextures; - const maxCubemapSize = capabilities.maxCubemapSize; - const maxTextureSize = capabilities.maxTextureSize; - const maxSamples = capabilities.maxSamples; const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); @@ -22123,7 +23559,7 @@ } - function getInternalFormat( internalFormatName, glFormat, glType, encoding, forceLinearEncoding = false ) { + function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { if ( isWebGL2 === false ) return glFormat; @@ -22137,35 +23573,48 @@ let internalFormat = glFormat; - if ( glFormat === 6403 ) { + if ( glFormat === _gl.RED ) { + + if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; + + } + + if ( glFormat === _gl.RED_INTEGER ) { - if ( glType === 5126 ) internalFormat = 33326; - if ( glType === 5131 ) internalFormat = 33325; - if ( glType === 5121 ) internalFormat = 33321; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; + if ( glType === _gl.INT ) internalFormat = _gl.R32I; } - if ( glFormat === 33319 ) { + if ( glFormat === _gl.RG ) { - if ( glType === 5126 ) internalFormat = 33328; - if ( glType === 5131 ) internalFormat = 33327; - if ( glType === 5121 ) internalFormat = 33323; + if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; } - if ( glFormat === 6408 ) { + if ( glFormat === _gl.RGBA ) { - if ( glType === 5126 ) internalFormat = 34836; - if ( glType === 5131 ) internalFormat = 34842; - if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding && forceLinearEncoding === false ) ? 35907 : 32856; - if ( glType === 32819 ) internalFormat = 32854; - if ( glType === 32820 ) internalFormat = 32855; + const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); + + if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; + if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; + if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; } - if ( internalFormat === 33325 || internalFormat === 33326 || - internalFormat === 33327 || internalFormat === 33328 || - internalFormat === 34842 || internalFormat === 34836 ) { + if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || + internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || + internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { extensions.get( 'EXT_color_buffer_float' ); @@ -22207,11 +23656,11 @@ if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - return 9728; + return _gl.NEAREST; } - return 9729; + return _gl.LINEAR; } @@ -22321,14 +23770,32 @@ for ( let i = 0; i < 6; i ++ ) { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); } } else { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); @@ -22385,9 +23852,9 @@ const textureUnit = textureUnits; - if ( textureUnit >= maxTextures ) { + if ( textureUnit >= capabilities.maxTextures ) { - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); + console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); } @@ -22414,7 +23881,7 @@ array.push( texture.premultiplyAlpha ); array.push( texture.flipY ); array.push( texture.unpackAlignment ); - array.push( texture.encoding ); + array.push( texture.colorSpace ); return array.join(); @@ -22449,7 +23916,7 @@ } - state.bindTexture( 3553, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22464,7 +23931,7 @@ } - state.bindTexture( 35866, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22479,7 +23946,7 @@ } - state.bindTexture( 32879, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22494,50 +23961,61 @@ } - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } const wrappingToGL = { - [ RepeatWrapping ]: 10497, - [ ClampToEdgeWrapping ]: 33071, - [ MirroredRepeatWrapping ]: 33648 + [ RepeatWrapping ]: _gl.REPEAT, + [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, + [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT }; const filterToGL = { - [ NearestFilter ]: 9728, - [ NearestMipmapNearestFilter ]: 9984, - [ NearestMipmapLinearFilter ]: 9986, + [ 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 + }; - [ LinearFilter ]: 9729, - [ LinearMipmapNearestFilter ]: 9985, - [ LinearMipmapLinearFilter ]: 9987 + 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 }; function setTextureParameters( textureType, texture, supportsMips ) { if ( supportsMips ) { - _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); } - _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); } else { - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); } @@ -22547,8 +24025,8 @@ } - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { @@ -22558,10 +24036,19 @@ } + 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 ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + if ( texture.magFilter === NearestFilter ) return; + if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only @@ -22658,43 +24145,47 @@ function uploadTexture( textureProperties, texture, slot ) { - let textureType = 3553; + let textureType = _gl.TEXTURE_2D; - if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = 35866; - if ( texture.isData3DTexture ) textureType = 32879; + if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; + if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( textureType, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); + let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); image = verifyColorSpace( texture, image ); const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ); + glFormat = utils.convert( texture.format, texture.colorSpace ); let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); setTextureParameters( textureType, texture, supportsMips ); let mipmap; const mipmaps = texture.mipmaps; - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); + const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); const levels = getMipLevels( texture, image, supportsMips ); @@ -22702,25 +24193,25 @@ // populate depth texture with dummy data - glInternalFormat = 6402; + glInternalFormat = _gl.DEPTH_COMPONENT; if ( isWebGL2 ) { if ( texture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( texture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } else if ( texture.type === UnsignedInt248Type ) { - glInternalFormat = 35056; + glInternalFormat = _gl.DEPTH24_STENCIL8; } else { - glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D + glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D } @@ -22736,7 +24227,7 @@ // validation checks for WebGL 1 - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT @@ -22752,11 +24243,11 @@ } - if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // Depth stencil textures need the DEPTH_STENCIL internal format // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = 34041; + glInternalFormat = _gl.DEPTH_STENCIL; // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. @@ -22778,11 +24269,11 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, 1, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); } @@ -22798,7 +24289,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22808,11 +24299,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22826,15 +24317,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); } @@ -22846,7 +24337,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); } @@ -22860,11 +24351,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); + state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); } else { - state.compressedTexImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); + state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); } @@ -22878,11 +24369,11 @@ if ( useTexStorage ) { - state.texSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); } else { - state.texImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); } @@ -22894,7 +24385,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22908,11 +24399,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -22926,11 +24417,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22946,15 +24437,15 @@ if ( allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 35866, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22964,15 +24455,15 @@ if ( allocateMemory ) { - state.texStorage3D( 32879, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 32879, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22982,7 +24473,7 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } else { @@ -22990,7 +24481,7 @@ for ( let i = 0; i < levels; i ++ ) { - state.texImage2D( 3553, i, glInternalFormat, width, height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); width >>= 1; height >>= 1; @@ -23013,7 +24504,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -23023,11 +24514,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, glFormat, glType, mipmap ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); } else { - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); } @@ -23041,15 +24532,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, glFormat, glType, image ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); } else { - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); } @@ -23080,18 +24571,22 @@ const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); @@ -23102,7 +24597,7 @@ if ( ! isCompressed && ! isDataTexture ) { - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); + cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); } else { @@ -23116,15 +24611,15 @@ const image = cubeImage[ 0 ], supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ), + glFormat = utils.convert( texture.format, texture.colorSpace ), glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); let levels = getMipLevels( texture, image, supportsMips ); - setTextureParameters( 34067, texture, supportsMips ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); let mipmaps; @@ -23132,7 +24627,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 34067, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); } @@ -23150,11 +24645,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -23168,11 +24663,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -23194,7 +24689,7 @@ if ( mipmaps.length > 0 ) levels ++; - state.texStorage2D( 34067, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); } @@ -23204,11 +24699,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); } @@ -23219,11 +24714,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); } @@ -23233,11 +24728,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); } @@ -23247,11 +24742,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); } @@ -23266,7 +24761,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { // We assume images for cube map have the same size. - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23283,40 +24778,43 @@ // Render targets // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { + function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const renderTargetProperties = properties.get( renderTarget ); if ( ! renderTargetProperties.__hasExternalTextures ) { - if ( textureTarget === 32879 || textureTarget === 35866 ) { + const width = Math.max( 1, renderTarget.width >> level ); + const height = Math.max( 1, renderTarget.height >> level ); - state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); + if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { + + state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); } else { - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); } } - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - } else if ( textureTarget === 3553 || ( textureTarget >= 34069 && textureTarget <= 34074 ) ) { // see #24753 + } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23324,11 +24822,11 @@ // Setup storage for internal depth/stencil buffers and bind to correct framebuffer function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - _gl.bindRenderbuffer( 36161, renderbuffer ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - let glInternalFormat = 33189; + let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; if ( isMultisample || useMultisampledRTT( renderTarget ) ) { @@ -23338,11 +24836,11 @@ if ( depthTexture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( depthTexture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } @@ -23352,21 +24850,21 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { @@ -23374,20 +24872,20 @@ if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else { @@ -23397,22 +24895,22 @@ const texture = textures[ i ]; - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const samples = getRenderTargetSamples( renderTarget ); if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } @@ -23420,7 +24918,7 @@ } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); } @@ -23430,7 +24928,7 @@ const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { @@ -23458,11 +24956,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 36096, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23470,11 +24968,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 33306, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23506,7 +25004,7 @@ for ( let i = 0; i < 6; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); @@ -23514,7 +25012,7 @@ } else { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); @@ -23522,7 +25020,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23533,7 +25031,7 @@ if ( colorTexture !== undefined ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, 36064, 3553 ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); } @@ -23580,13 +25078,41 @@ for ( let i = 0; i < 6; i ++ ) { - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer[ i ] = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + + } } } else { - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + + } if ( isMultipleRenderTargets ) { @@ -23623,26 +25149,26 @@ renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); renderTargetProperties.__webglColorRenderbuffer = []; - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { const texture = textures[ i ]; renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, renderTarget.isXRRenderTarget === true ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); if ( renderTarget.depthBuffer ) { @@ -23651,7 +25177,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23661,18 +25187,30 @@ if ( isCube ) { - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, texture, supportsMips ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); for ( let i = 0; i < 6; i ++ ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + 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, supportsMips ) ) { - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23687,13 +25225,13 @@ const attachment = textures[ i ]; const attachmentProperties = properties.get( attachment ); - state.bindTexture( 3553, attachmentProperties.__webglTexture ); - setTextureParameters( 3553, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); + state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - generateMipmap( 3553 ); + generateMipmap( _gl.TEXTURE_2D ); } @@ -23703,13 +25241,13 @@ } else { - let glTextureType = 3553; + let glTextureType = _gl.TEXTURE_2D; if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { if ( isWebGL2 ) { - glTextureType = renderTarget.isWebGL3DRenderTarget ? 32879 : 35866; + glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; } else { @@ -23721,7 +25259,20 @@ state.bindTexture( glTextureType, textureProperties.__webglTexture ); setTextureParameters( glTextureType, texture, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); + + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); + + } + + } else { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); + + } if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { @@ -23755,7 +25306,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; + const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; const webglTexture = properties.get( texture ).__webglTexture; state.bindTexture( target, webglTexture ); @@ -23775,9 +25326,9 @@ const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; const width = renderTarget.width; const height = renderTarget.height; - let mask = 16384; + let mask = _gl.COLOR_BUFFER_BIT; const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? 33306 : 36096; + const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; const renderTargetProperties = properties.get( renderTarget ); const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); @@ -23786,22 +25337,22 @@ for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, null, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); } } - state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { - invalidationArray.push( 36064 + i ); + invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); if ( renderTarget.depthBuffer ) { @@ -23813,63 +25364,63 @@ if ( ignoreDepthValues === false ) { - if ( renderTarget.depthBuffer ) mask |= 256; - if ( renderTarget.stencilBuffer ) mask |= 1024; + if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; + if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; } if ( isMultipleRenderTargets ) { - _gl.framebufferRenderbuffer( 36008, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } if ( ignoreDepthValues === true ) { - _gl.invalidateFramebuffer( 36008, [ depthStyle ] ); - _gl.invalidateFramebuffer( 36009, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); } if ( isMultipleRenderTargets ) { const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( 36009, 36064, 3553, webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); } - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); + _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); if ( supportsInvalidateFramebuffer ) { - _gl.invalidateFramebuffer( 36008, invalidationArray ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); } } - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, null ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments if ( isMultipleRenderTargets ) { for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + 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( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, webglTexture, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); } } - state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); } @@ -23877,7 +25428,7 @@ function getRenderTargetSamples( renderTarget ) { - return Math.min( maxSamples, renderTarget.samples ); + return Math.min( capabilities.maxSamples, renderTarget.samples ); } @@ -23906,17 +25457,17 @@ function verifyColorSpace( texture, image ) { - const encoding = texture.encoding; + const colorSpace = texture.colorSpace; const format = texture.format; const type = texture.type; if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - if ( encoding !== LinearEncoding ) { + if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { // sRGB - if ( encoding === sRGBEncoding ) { + if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { if ( isWebGL2 === false ) { @@ -23953,7 +25504,7 @@ } else { - console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding ); + console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); } @@ -23986,24 +25537,26 @@ const isWebGL2 = capabilities.isWebGL2; - function convert( p, encoding = null ) { + function convert( p, colorSpace = NoColorSpace ) { let extension; - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; + const transfer = ColorManagement.getTransfer( colorSpace ); - if ( p === ByteType ) return 5120; - if ( p === ShortType ) return 5122; - if ( p === UnsignedShortType ) return 5123; - if ( p === IntType ) return 5124; - if ( p === UnsignedIntType ) return 5125; - if ( p === FloatType ) return 5126; + if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; + if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; + + if ( p === ByteType ) return gl.BYTE; + if ( p === ShortType ) return gl.SHORT; + if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; + if ( p === IntType ) return gl.INT; + if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; + if ( p === FloatType ) return gl.FLOAT; if ( p === HalfFloatType ) { - if ( isWebGL2 ) return 5131; + if ( isWebGL2 ) return gl.HALF_FLOAT; extension = extensions.get( 'OES_texture_half_float' ); @@ -24019,21 +25572,12 @@ } - if ( p === AlphaFormat ) return 6406; - if ( p === RGBAFormat ) return 6408; - if ( p === LuminanceFormat ) return 6409; - if ( p === LuminanceAlphaFormat ) return 6410; - if ( p === DepthFormat ) return 6402; - if ( p === DepthStencilFormat ) return 34041; - - // @deprecated since r137 - - if ( p === RGBFormat ) { - - console.warn( 'THREE.WebGLRenderer: THREE.RGBFormat has been removed. Use THREE.RGBAFormat instead. https://github.com/mrdoob/three.js/pull/23228' ); - return 6408; - - } + if ( p === AlphaFormat ) return gl.ALPHA; + if ( p === RGBAFormat ) return gl.RGBA; + if ( p === LuminanceFormat ) return gl.LUMINANCE; + if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; + if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; + if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; // WebGL 1 sRGB fallback @@ -24055,17 +25599,17 @@ // WebGL2 formats. - if ( p === RedFormat ) return 6403; - if ( p === RedIntegerFormat ) return 36244; - if ( p === RGFormat ) return 33319; - if ( p === RGIntegerFormat ) return 33320; - if ( p === RGBAIntegerFormat ) return 36249; + if ( p === RedFormat ) return gl.RED; + if ( p === RedIntegerFormat ) return gl.RED_INTEGER; + if ( p === RGFormat ) return gl.RG; + if ( p === RGIntegerFormat ) return gl.RG_INTEGER; + if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; // S3TC if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - if ( encoding === sRGBEncoding ) { + if ( transfer === SRGBTransfer ) { extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); @@ -24150,8 +25694,8 @@ if ( extension !== null ) { - if ( p === RGB_ETC2_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; + if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; } else { @@ -24173,20 +25717,20 @@ if ( extension !== null ) { - if ( p === RGBA_ASTC_4x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; } else { @@ -24198,13 +25742,36 @@ // BPTC - if ( p === RGBA_BPTC_Format ) { + if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { extension = extensions.get( 'EXT_texture_compression_bptc' ); if ( extension !== null ) { - if ( p === RGBA_BPTC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; + if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; + + } else { + + return null; + + } + + } + + // RGTC + + if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { + + extension = extensions.get( 'EXT_texture_compression_rgtc' ); + + if ( extension !== null ) { + + if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; + if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; + if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; + if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; } else { @@ -24218,7 +25785,7 @@ if ( p === UnsignedInt248Type ) { - if ( isWebGL2 ) return 34042; + if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; extension = extensions.get( 'WEBGL_depth_texture' ); @@ -24440,6 +26007,7 @@ joint.matrix.fromArray( jointPose.transform.matrix ); joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); + joint.matrixWorldNeedsUpdate = true; joint.jointRadius = jointPose.radius; } @@ -24488,6 +26056,7 @@ grip.matrix.fromArray( gripPose.transform.matrix ); grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); + grip.matrixWorldNeedsUpdate = true; if ( gripPose.linearVelocity ) { @@ -24532,6 +26101,7 @@ targetRay.matrix.fromArray( inputPose.transform.matrix ); targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); + targetRay.matrixWorldNeedsUpdate = true; if ( inputPose.linearVelocity ) { @@ -24607,38 +26177,6 @@ } - class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isDepthTexture = true; - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - } - - - } - class WebXRManager extends EventDispatcher { constructor( renderer, gl ) { @@ -24648,10 +26186,13 @@ const scope = this; let session = null; + let framebufferScaleFactor = 1.0; let referenceSpace = null; let referenceSpaceType = 'local-floor'; + // Set default foveation to maximum. + let foveation = 1.0; let customReferenceSpace = null; let pose = null; @@ -24666,8 +26207,8 @@ const controllers = []; const controllerInputSources = []; - const planes = new Set(); - const planesLastChangedTimes = new Map(); + const currentSize = new Vector2(); + let currentPixelRatio = null; // @@ -24681,9 +26222,9 @@ const cameras = [ cameraL, cameraR ]; - const cameraVR = new ArrayCamera(); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); + const cameraXR = new ArrayCamera(); + cameraXR.layers.enable( 1 ); + cameraXR.layers.enable( 2 ); let _currentDepthNear = null; let _currentDepthFar = null; @@ -24756,6 +26297,7 @@ if ( controller !== undefined ) { + controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); controller.dispatchEvent( { type: event.type, data: event.inputSource } ); } @@ -24804,6 +26346,9 @@ scope.isPresenting = false; + renderer.setPixelRatio( currentPixelRatio ); + renderer.setSize( currentSize.width, currentSize.height, false ); + scope.dispatchEvent( { type: 'sessionend' } ); } @@ -24891,11 +26436,14 @@ } + currentPixelRatio = renderer.getPixelRatio(); + renderer.getSize( currentSize ); + if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { const layerInit = { antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: attributes.alpha, + alpha: true, depth: attributes.depth, stencil: attributes.stencil, framebufferScaleFactor: framebufferScaleFactor @@ -24905,13 +26453,16 @@ session.updateRenderState( { baseLayer: glBaseLayer } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); + newRenderTarget = new WebGLRenderTarget( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, { format: RGBAFormat, type: UnsignedByteType, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, stencilBuffer: attributes.stencil } ); @@ -24924,14 +26475,14 @@ if ( attributes.depth ) { - glDepthFormat = attributes.stencil ? 35056 : 33190; + glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; } const projectionlayerInit = { - colorFormat: 32856, + colorFormat: gl.RGBA8, depthFormat: glDepthFormat, scaleFactor: framebufferScaleFactor }; @@ -24942,6 +26493,9 @@ session.updateRenderState( { layers: [ glProjLayer ] } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); + newRenderTarget = new WebGLRenderTarget( glProjLayer.textureWidth, glProjLayer.textureHeight, @@ -24950,7 +26504,7 @@ type: UnsignedByteType, depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), stencilBuffer: attributes.stencil, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, samples: attributes.antialias ? 4 : 0 } ); @@ -24961,18 +26515,27 @@ newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - // Set foveation to maximum. - this.setFoveation( 1.0 ); + this.setFoveation( foveation ); customReferenceSpace = null; referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); - animation.setContext( session ); - animation.start(); + animation.setContext( session ); + animation.start(); + + scope.isPresenting = true; + + scope.dispatchEvent( { type: 'sessionstart' } ); + + } + + }; - scope.isPresenting = true; + this.getEnvironmentBlendMode = function () { - scope.dispatchEvent( { type: 'sessionstart' } ); + if ( session !== null ) { + + return session.environmentBlendMode; } @@ -25101,6 +26664,7 @@ const bottom2 = bottomFov * far / far2 * near2; camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); } @@ -25124,27 +26688,27 @@ if ( session === null ) return; - cameraVR.near = cameraR.near = cameraL.near = camera.near; - cameraVR.far = cameraR.far = cameraL.far = camera.far; + cameraXR.near = cameraR.near = cameraL.near = camera.near; + cameraXR.far = cameraR.far = cameraL.far = camera.far; - if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { + if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { // Note that the new renderState won't apply until the next frame. See #18320 session.updateRenderState( { - depthNear: cameraVR.near, - depthFar: cameraVR.far + depthNear: cameraXR.near, + depthFar: cameraXR.far } ); - _currentDepthNear = cameraVR.near; - _currentDepthFar = cameraVR.far; + _currentDepthNear = cameraXR.near; + _currentDepthFar = cameraXR.far; } const parent = camera.parent; - const cameras = cameraVR.cameras; + const cameras = cameraXR.cameras; - updateCamera( cameraVR, parent ); + updateCamera( cameraXR, parent ); for ( let i = 0; i < cameras.length; i ++ ) { @@ -25152,86 +26716,94 @@ } - cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); + // update projection matrix for proper view frustum culling - // update user camera and its children + if ( cameras.length === 2 ) { - camera.matrix.copy( cameraVR.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + setProjectionFromUnion( cameraXR, cameraL, cameraR ); - const children = camera.children; + } else { - for ( let i = 0, l = children.length; i < l; i ++ ) { + // assume single camera setup (AR) - children[ i ].updateMatrixWorld( true ); + cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); } - // update projection matrix for proper view frustum culling + // update user camera and its children - if ( cameras.length === 2 ) { + updateUserCamera( camera, cameraXR, parent ); + + }; + + function updateUserCamera( camera, cameraXR, parent ) { - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + if ( parent === null ) { + + camera.matrix.copy( cameraXR.matrixWorld ); } else { - // assume single camera setup (AR) + camera.matrix.copy( parent.matrixWorld ); + camera.matrix.invert(); + camera.matrix.multiply( cameraXR.matrixWorld ); + + } + + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + camera.updateMatrixWorld( true ); + + camera.projectionMatrix.copy( cameraXR.projectionMatrix ); + camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); + if ( camera.isPerspectiveCamera ) { + + camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); + camera.zoom = 1; } - }; + } this.getCamera = function () { - return cameraVR; + return cameraXR; }; this.getFoveation = function () { - if ( glProjLayer !== null ) { - - return glProjLayer.fixedFoveation; - - } - - if ( glBaseLayer !== null ) { + if ( glProjLayer === null && glBaseLayer === null ) { - return glBaseLayer.fixedFoveation; + return undefined; } - return undefined; + return foveation; }; - this.setFoveation = function ( foveation ) { + this.setFoveation = function ( value ) { // 0 = no foveation = full resolution // 1 = maximum foveation = the edges render at lower resolution + foveation = value; + if ( glProjLayer !== null ) { - glProjLayer.fixedFoveation = foveation; + glProjLayer.fixedFoveation = value; } if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - glBaseLayer.fixedFoveation = foveation; + glBaseLayer.fixedFoveation = value; } }; - this.getPlanes = function () { - - return planes; - - }; - // Animation Loop let onAnimationFrameCallback = null; @@ -25252,14 +26824,14 @@ } - let cameraVRNeedsUpdate = false; + let cameraXRNeedsUpdate = false; - // check if it's necessary to rebuild cameraVR's camera list + // check if it's necessary to rebuild cameraXR's camera list - if ( views.length !== cameraVR.cameras.length ) { + if ( views.length !== cameraXR.cameras.length ) { - cameraVR.cameras.length = 0; - cameraVRNeedsUpdate = true; + cameraXR.cameras.length = 0; + cameraXRNeedsUpdate = true; } @@ -25304,18 +26876,21 @@ } camera.matrix.fromArray( view.transform.matrix ); + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); camera.projectionMatrix.fromArray( view.projectionMatrix ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); if ( i === 0 ) { - cameraVR.matrix.copy( camera.matrix ); + cameraXR.matrix.copy( camera.matrix ); + cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); } - if ( cameraVRNeedsUpdate === true ) { + if ( cameraXRNeedsUpdate === true ) { - cameraVR.cameras.push( camera ); + cameraXR.cameras.push( camera ); } @@ -25342,60 +26917,7 @@ if ( frame.detectedPlanes ) { - scope.dispatchEvent( { type: 'planesdetected', data: frame.detectedPlanes } ); - - let planesToRemove = null; - - for ( const plane of planes ) { - - if ( ! frame.detectedPlanes.has( plane ) ) { - - if ( planesToRemove === null ) { - - planesToRemove = []; - - } - - planesToRemove.push( plane ); - - } - - } - - if ( planesToRemove !== null ) { - - for ( const plane of planesToRemove ) { - - planes.delete( plane ); - planesLastChangedTimes.delete( plane ); - scope.dispatchEvent( { type: 'planeremoved', data: plane } ); - - } - - } - - for ( const plane of frame.detectedPlanes ) { - - if ( ! planes.has( plane ) ) { - - planes.add( plane ); - planesLastChangedTimes.set( plane, frame.lastChangedTime ); - scope.dispatchEvent( { type: 'planeadded', data: plane } ); - - } else { - - const lastKnownTime = planesLastChangedTimes.get( plane ); - - if ( plane.lastChangedTime > lastKnownTime ) { - - planesLastChangedTimes.set( plane, plane.lastChangedTime ); - scope.dispatchEvent( { type: 'planechanged', data: plane } ); - - } - - } - - } + scope.dispatchEvent( { type: 'planesdetected', data: frame } ); } @@ -25421,6 +26943,18 @@ function WebGLMaterials( renderer, properties ) { + function refreshTransformUniform( map, uniform ) { + + if ( map.matrixAutoUpdate === true ) { + + map.updateMatrix(); + + } + + uniform.value.copy( map.matrix ); + + } + function refreshFogUniforms( uniforms, fog ) { fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); @@ -25538,25 +27072,56 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } 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; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + + if ( material.side === BackSide ) { + + uniforms.bumpScale.value *= - 1; + + } + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + + refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); + + uniforms.normalScale.value.copy( material.normalScale ); + + if ( material.side === BackSide ) { + + 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; @@ -25566,13 +27131,7 @@ uniforms.emissiveMap.value = material.emissiveMap; - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); } @@ -25580,6 +27139,8 @@ uniforms.specularMap.value = material.specularMap; + refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25607,10 +27168,12 @@ uniforms.lightMap.value = material.lightMap; // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer.physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; + refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); + } if ( material.aoMap ) { @@ -25618,175 +27181,27 @@ uniforms.aoMap.value = material.aoMap; uniforms.aoMapIntensity.value = material.aoMapIntensity; - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. displacementMap map - // 4. normal map - // 5. bump map - // 6. roughnessMap map - // 7. metalnessMap map - // 8. alphaMap map - // 9. emissiveMap map - // 10. clearcoat map - // 11. clearcoat normal map - // 12. clearcoat roughnessMap map - // 13. iridescence map - // 14. iridescence thickness map - // 15. specular intensity map - // 16. specular tint map - // 17. transmission map - // 18. thickness map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.roughnessMap ) { - - uvScaleMap = material.roughnessMap; - - } else if ( material.metalnessMap ) { - - uvScaleMap = material.metalnessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } else if ( material.clearcoatMap ) { - - uvScaleMap = material.clearcoatMap; - - } else if ( material.clearcoatNormalMap ) { - - uvScaleMap = material.clearcoatNormalMap; - - } else if ( material.clearcoatRoughnessMap ) { - - uvScaleMap = material.clearcoatRoughnessMap; - - } else if ( material.iridescenceMap ) { - - uvScaleMap = material.iridescenceMap; - - } else if ( material.iridescenceThicknessMap ) { - - uvScaleMap = material.iridescenceThicknessMap; - - } else if ( material.specularIntensityMap ) { - - uvScaleMap = material.specularIntensityMap; - - } else if ( material.specularColorMap ) { - - uvScaleMap = material.specularColorMap; - - } else if ( material.transmissionMap ) { - - uvScaleMap = material.transmissionMap; - - } else if ( material.thicknessMap ) { - - uvScaleMap = material.thicknessMap; - - } else if ( material.sheenColorMap ) { - - uvScaleMap = material.sheenColorMap; - - } else if ( material.sheenRoughnessMap ) { - - uvScaleMap = material.sheenRoughnessMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - // uv repeat and offset setting priorities for uv2 - // 1. ao map - // 2. light map - - let uv2ScaleMap; - - if ( material.aoMap ) { - - uv2ScaleMap = material.aoMap; - - } else if ( material.lightMap ) { - - uv2ScaleMap = material.lightMap; + refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); } - if ( uv2ScaleMap !== undefined ) { - - // backwards compatibility - if ( uv2ScaleMap.isWebGLRenderTarget ) { - - uv2ScaleMap = uv2ScaleMap.texture; + } - } + function refreshUniformsLine( uniforms, material ) { - if ( uv2ScaleMap.matrixAutoUpdate === true ) { + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - uv2ScaleMap.updateMatrix(); + if ( material.map ) { - } + uniforms.map.value = material.map; - uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); + refreshTransformUniform( material.map, uniforms.mapTransform ); } } - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } - function refreshUniformsDash( uniforms, material ) { uniforms.dashSize.value = material.dashSize; @@ -25806,12 +27221,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.uvTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25820,34 +27239,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsSprites( uniforms, material ) { @@ -25860,12 +27251,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25874,34 +27269,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsPhong( uniforms, material ) { @@ -25923,18 +27290,23 @@ function refreshUniformsStandard( uniforms, material ) { - uniforms.roughness.value = material.roughness; uniforms.metalness.value = material.metalness; - if ( material.roughnessMap ) { + if ( material.metalnessMap ) { - uniforms.roughnessMap.value = material.roughnessMap; + uniforms.metalnessMap.value = material.metalnessMap; + + refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); } - if ( material.metalnessMap ) { + uniforms.roughness.value = material.roughness; - uniforms.metalnessMap.value = material.metalnessMap; + if ( material.roughnessMap ) { + + uniforms.roughnessMap.value = material.roughnessMap; + + refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); } @@ -25963,12 +27335,16 @@ uniforms.sheenColorMap.value = material.sheenColorMap; + refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); + } if ( material.sheenRoughnessMap ) { uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; + refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); + } } @@ -25982,19 +27358,26 @@ 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.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; + refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); + + uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); + if ( material.side === BackSide ) { uniforms.clearcoatNormalScale.value.negate(); @@ -26016,12 +27399,16 @@ uniforms.iridescenceMap.value = material.iridescenceMap; + refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); + } if ( material.iridescenceThicknessMap ) { uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; + refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); + } } @@ -26036,6 +27423,8 @@ uniforms.transmissionMap.value = material.transmissionMap; + refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); + } uniforms.thickness.value = material.thickness; @@ -26044,6 +27433,8 @@ uniforms.thicknessMap.value = material.thicknessMap; + refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); + } uniforms.attenuationDistance.value = material.attenuationDistance; @@ -26051,19 +27442,37 @@ } - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularColor.value.copy( material.specularColor ); + if ( material.anisotropy > 0 ) { - if ( material.specularIntensityMap ) { + uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); - uniforms.specularIntensityMap.value = material.specularIntensityMap; + 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 ); + } } @@ -26080,9 +27489,11 @@ function refreshUniformsDistance( uniforms, material ) { - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; + const light = properties.get( material ).light; + + uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); + uniforms.nearDistance.value = light.shadow.camera.near; + uniforms.farDistance.value = light.shadow.camera.far; } @@ -26099,7 +27510,7 @@ let updateList = {}; let allocatedBindingPoints = []; - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( 35375 ) : 0; // binding points are global whereas block indices are per shader program + const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program function bind( uniformsGroup, program ) { @@ -26153,10 +27564,10 @@ const size = uniformsGroup.__size; const usage = uniformsGroup.usage; - gl.bindBuffer( 35345, buffer ); - gl.bufferData( 35345, size, usage ); - gl.bindBuffer( 35345, null ); - gl.bindBufferBase( 35345, bindingPointIndex, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); + gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); + gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); return buffer; @@ -26187,50 +27598,64 @@ const uniforms = uniformsGroup.uniforms; const cache = uniformsGroup.__cache; - gl.bindBuffer( 35345, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - const uniform = uniforms[ i ]; + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // partly update the buffer if necessary + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - if ( hasUniformChanged( uniform, i, cache ) === true ) { + const uniform = uniformArray[ j ]; - const value = uniform.value; - const offset = uniform.__offset; + if ( hasUniformChanged( uniform, i, j, cache ) === true ) { - if ( typeof value === 'number' ) { + const offset = uniform.__offset; - uniform.__data[ 0 ] = value; - gl.bufferSubData( 35345, offset, uniform.__data ); + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - } else { + let arrayOffset = 0; - if ( uniform.value.isMatrix3 ) { + for ( let k = 0; k < values.length; k ++ ) { - // manually converting 3x3 to 3x4 + const value = values[ k ]; - uniform.__data[ 0 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 1 ] = uniform.value.elements[ 1 ]; - uniform.__data[ 2 ] = uniform.value.elements[ 2 ]; - uniform.__data[ 3 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 4 ] = uniform.value.elements[ 3 ]; - uniform.__data[ 5 ] = uniform.value.elements[ 4 ]; - uniform.__data[ 6 ] = uniform.value.elements[ 5 ]; - uniform.__data[ 7 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 8 ] = uniform.value.elements[ 6 ]; - uniform.__data[ 9 ] = uniform.value.elements[ 7 ]; - uniform.__data[ 10 ] = uniform.value.elements[ 8 ]; - uniform.__data[ 11 ] = uniform.value.elements[ 0 ]; + const info = getUniformSize( value ); - } else { + // TODO add integer and struct support + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + uniform.__data[ 0 ] = value; + gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); - value.toArray( uniform.__data ); + } else if ( value.isMatrix3 ) { + + // manually converting 3x3 to 3x4 + + 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; + + } } - gl.bufferSubData( 35345, offset, uniform.__data ); + gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); } @@ -26238,25 +27663,26 @@ } - gl.bindBuffer( 35345, null ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); } - function hasUniformChanged( uniform, index, cache ) { + function hasUniformChanged( uniform, index, indexArray, cache ) { const value = uniform.value; + const indexString = index + '_' + indexArray; - if ( cache[ index ] === undefined ) { + if ( cache[ indexString ] === undefined ) { // cache entry does not exist so far - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - cache[ index ] = value; + cache[ indexString ] = value; } else { - cache[ index ] = value.clone(); + cache[ indexString ] = value.clone(); } @@ -26264,21 +27690,21 @@ } else { + const cachedObject = cache[ indexString ]; + // compare current value with cached entry - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - if ( cache[ index ] !== value ) { + if ( cachedObject !== value ) { - cache[ index ] = value; + cache[ indexString ] = value; return true; } } else { - const cachedObject = cache[ index ]; - if ( cachedObject.equals( value ) === false ) { cachedObject.copy( value ); @@ -26303,1305 +27729,1659 @@ let offset = 0; // global buffer offset in bytes const chunkSize = 16; // size of a chunk in bytes - let chunkOffset = 0; // offset within a single chunk in bytes for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - const uniform = uniforms[ i ]; - const info = getUniformSize( uniform ); + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // the following two properties will be used for partial buffer updates + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; + const uniform = uniformArray[ j ]; - // + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; + + for ( let k = 0, kl = values.length; k < kl; k ++ ) { - if ( i > 0 ) { + const value = values[ k ]; - chunkOffset = offset % chunkSize; + const info = getUniformSize( value ); - const remainingSizeInChunk = chunkSize - chunkOffset; + // Calculate the chunk offset + const chunkOffsetUniform = offset % chunkSize; - // check for chunk overflow + // Check for chunk overflow + if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { - if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) { + // Add padding and adjust offset + offset += ( chunkSize - chunkOffsetUniform ); - // add padding and adjust offset + } + + // the following two properties will be used for partial buffer updates - offset += ( chunkSize - chunkOffset ); + uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); uniform.__offset = offset; + + // Update the global offset + offset += info.storage; + + } } - offset += info.storage; - } // ensure correct final padding - chunkOffset = offset % chunkSize; + const chunkOffset = offset % chunkSize; + + if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); + + // + + uniformsGroup.__size = offset; + uniformsGroup.__cache = {}; + + return this; + + } + + function getUniformSize( value ) { + + const info = { + boundary: 0, // bytes + storage: 0 // bytes + }; + + // determine sizes according to STD140 + + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + // float/int/bool + + info.boundary = 4; + info.storage = 4; + + } else if ( value.isVector2 ) { + + // vec2 + + info.boundary = 8; + info.storage = 8; + + } else if ( value.isVector3 || value.isColor ) { + + // 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 ) { + + // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + + info.boundary = 48; + info.storage = 48; + + } else if ( value.isMatrix4 ) { + + // mat4 + + info.boundary = 64; + info.storage = 64; + + } else if ( value.isTexture ) { + + console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + + } else { + + console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + + } + + return info; + + } + + function onUniformsGroupsDispose( event ) { + + const uniformsGroup = event.target; + + uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + + const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); + allocatedBindingPoints.splice( index, 1 ); + + gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + + delete buffers[ uniformsGroup.id ]; + delete updateList[ uniformsGroup.id ]; + + } + + function dispose() { + + for ( const id in buffers ) { + + 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 = true, + alpha = false, + antialias = false, + premultipliedAlpha = true, + preserveDrawingBuffer = false, + powerPreference = 'default', + failIfMajorPerformanceCaveat = false, + } = parameters; + + this.isWebGLRenderer = true; + + let _alpha; + + if ( context !== null ) { + + _alpha = context.getContextAttributes().alpha; + + } else { + + _alpha = alpha; + + } + + const uintClearColor = new Uint32Array( 4 ); + const intClearColor = new Int32Array( 4 ); + + let currentRenderList = null; + let currentRenderState = null; + + // render() can be called from within a callback triggered by another render. + // We track this so that the nested render call gets its list and state isolated from the parent render call. + + const renderListStack = []; + const renderStateStack = []; + + // public properties + + this.domElement = canvas; + + // Debug configuration container + this.debug = { + + /** + * 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; + + // physically based shading + + this._outputColorSpace = SRGBColorSpace; + + // physical lights + + this._useLegacyLights = false; + + // tone mapping + + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; + + // internal properties + + const _this = this; + + let _isContextLost = false; + + // internal state cache + + let _currentActiveCubeFace = 0; + let _currentActiveMipmapLevel = 0; + let _currentRenderTarget = null; + let _currentMaterialId = - 1; + + let _currentCamera = null; + + const _currentViewport = new Vector4(); + const _currentScissor = new Vector4(); + let _currentScissorTest = null; + + const _currentClearColor = new Color( 0x000000 ); + let _currentClearAlpha = 0; + + // + + let _width = canvas.width; + let _height = canvas.height; + + let _pixelRatio = 1; + let _opaqueSort = null; + let _transparentSort = null; + + const _viewport = new Vector4( 0, 0, _width, _height ); + const _scissor = new Vector4( 0, 0, _width, _height ); + let _scissorTest = false; + + // frustum + + const _frustum = new Frustum(); + + // clipping + + let _clippingEnabled = false; + let _localClippingEnabled = false; + + // transmission + + let _transmissionRenderTarget = null; + + // camera matrices cache + + const _projScreenMatrix = new Matrix4(); + + const _vector2 = new Vector2(); + const _vector3 = new Vector3(); + + const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + + function getTargetPixelRatio() { + + return _currentRenderTarget === null ? _pixelRatio : 1; + + } + + // initialize + + let _gl = context; + + function getContext( contextNames, contextAttributes ) { + + for ( let i = 0; i < contextNames.length; i ++ ) { + + const contextName = contextNames[ i ]; + const context = canvas.getContext( contextName, contextAttributes ); + if ( context !== null ) return context; + + } + + return null; + + } + + try { + + const contextAttributes = { + alpha: true, + depth, + stencil, + antialias, + premultipliedAlpha, + preserveDrawingBuffer, + powerPreference, + failIfMajorPerformanceCaveat, + }; + + // OffscreenCanvas does not have setAttribute, see #22811 + if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + + // event listeners must be registered before WebGL context is created, see #12753 + canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + + if ( _gl === null ) { + + const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + + if ( _this.isWebGL1Renderer === true ) { + + contextNames.shift(); + + } + + _gl = getContext( contextNames, contextAttributes ); + + if ( _gl === null ) { + + if ( getContext( contextNames ) ) { + + throw new Error( 'Error creating WebGL context with your selected attributes.' ); + + } else { + + throw new Error( 'Error creating WebGL context.' ); + + } + + } + + } + + if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 + + console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); + + } - if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); + // Some experimental-webgl implementations do not have getShaderPrecisionFormat - // + if ( _gl.getShaderPrecisionFormat === undefined ) { - uniformsGroup.__size = offset; - uniformsGroup.__cache = {}; + _gl.getShaderPrecisionFormat = function () { - return this; + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; - } + }; - function getUniformSize( uniform ) { + } - const value = uniform.value; + } catch ( error ) { - const info = { - boundary: 0, // bytes - storage: 0 // bytes - }; + console.error( 'THREE.WebGLRenderer: ' + error.message ); + throw error; - // determine sizes according to STD140 + } - if ( typeof value === 'number' ) { + let extensions, capabilities, state, info; + let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; + let programCache, materials, renderLists, renderStates, clipping, shadowMap; - // float/int + let background, morphtargets, bufferRenderer, indexedBufferRenderer; - info.boundary = 4; - info.storage = 4; + let utils, bindingStates, uniformsGroups; - } else if ( value.isVector2 ) { + function initGLContext() { - // vec2 + extensions = new WebGLExtensions( _gl ); - info.boundary = 8; - info.storage = 8; + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - } else if ( value.isVector3 || value.isColor ) { + extensions.init( capabilities ); - // vec3 + utils = new WebGLUtils( _gl, extensions, capabilities ); - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes + state = new WebGLState( _gl, extensions, capabilities ); - } else if ( value.isVector4 ) { + info = new WebGLInfo( _gl ); + properties = new WebGLProperties(); + textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); + cubemaps = new WebGLCubeMaps( _this ); + cubeuvmaps = new WebGLCubeUVMaps( _this ); + attributes = new WebGLAttributes( _gl, capabilities ); + bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); + geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); + objects = new WebGLObjects( _gl, geometries, attributes, info ); + morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); + clipping = new WebGLClipping( properties ); + programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); + materials = new WebGLMaterials( _this, properties ); + renderLists = new WebGLRenderLists(); + renderStates = new WebGLRenderStates( extensions, capabilities ); + background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); + shadowMap = new WebGLShadowMap( _this, objects, capabilities ); + uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - // vec4 + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - info.boundary = 16; - info.storage = 16; + info.programs = programCache.programs; - } else if ( value.isMatrix3 ) { + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.shadowMap = shadowMap; + _this.state = state; + _this.info = info; - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + } - info.boundary = 48; - info.storage = 48; + initGLContext(); - } else if ( value.isMatrix4 ) { + // xr - // mat4 + const xr = new WebXRManager( _this, _gl ); - info.boundary = 64; - info.storage = 64; + this.xr = xr; - } else if ( value.isTexture ) { + // API - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + this.getContext = function () { - } else { + return _gl; - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + }; - } + this.getContextAttributes = function () { - return info; + return _gl.getContextAttributes(); - } + }; - function onUniformsGroupsDispose( event ) { + this.forceContextLoss = function () { - const uniformsGroup = event.target; + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + }; - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); + this.forceContextRestore = function () { - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.restoreContext(); - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; + }; - } + this.getPixelRatio = function () { - function dispose() { + return _pixelRatio; - for ( const id in buffers ) { + }; - gl.deleteBuffer( buffers[ id ] ); + this.setPixelRatio = function ( value ) { - } + if ( value === undefined ) return; - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; + _pixelRatio = value; - } + this.setSize( _width, _height, false ); - return { + }; - bind: bind, - update: update, + this.getSize = function ( target ) { - dispose: dispose + return target.set( _width, _height ); - }; + }; - } + this.setSize = function ( width, height, updateStyle = true ) { - function createCanvasElement() { + if ( xr.isPresenting ) { - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - } + } - function WebGLRenderer( parameters = {} ) { + _width = width; + _height = height; - this.isWebGLRenderer = true; + canvas.width = Math.floor( width * _pixelRatio ); + canvas.height = Math.floor( height * _pixelRatio ); - const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), - _context = parameters.context !== undefined ? parameters.context : null, + if ( updateStyle === true ) { - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', - _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; - let _alpha; + } - if ( _context !== null ) { + this.setViewport( 0, 0, width, height ); - _alpha = _context.getContextAttributes().alpha; + }; - } else { + this.getDrawingBufferSize = function ( target ) { - _alpha = parameters.alpha !== undefined ? parameters.alpha : false; + return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - } + }; - let currentRenderList = null; - let currentRenderState = null; + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. + _width = width; + _height = height; - const renderListStack = []; - const renderStateStack = []; + _pixelRatio = pixelRatio; - // public properties + canvas.width = Math.floor( width * pixelRatio ); + canvas.height = Math.floor( height * pixelRatio ); - this.domElement = _canvas; + this.setViewport( 0, 0, width, height ); - // Debug configuration container - this.debug = { + }; - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true - }; + this.getCurrentViewport = function ( target ) { - // clearing + return target.copy( _currentViewport ); - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + }; - // scene graph + this.getViewport = function ( target ) { - this.sortObjects = true; + return target.copy( _viewport ); - // user-defined clipping + }; - this.clippingPlanes = []; - this.localClippingEnabled = false; + this.setViewport = function ( x, y, width, height ) { - // physically based shading + if ( x.isVector4 ) { - this.outputEncoding = LinearEncoding; + _viewport.set( x.x, x.y, x.z, x.w ); - // physical lights + } else { - this.physicallyCorrectLights = false; + _viewport.set( x, y, width, height ); - // tone mapping + } - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - // internal properties + }; - const _this = this; + this.getScissor = function ( target ) { - let _isContextLost = false; + return target.copy( _scissor ); - // internal state cache + }; - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; + this.setScissor = function ( x, y, width, height ) { - let _currentCamera = null; + if ( x.isVector4 ) { - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; + _scissor.set( x.x, x.y, x.z, x.w ); - // + } else { - let _width = _canvas.width; - let _height = _canvas.height; + _scissor.set( x, y, width, height ); - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; + } - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - // frustum + }; - const _frustum = new Frustum(); + this.getScissorTest = function () { - // clipping + return _scissorTest; - let _clippingEnabled = false; - let _localClippingEnabled = false; + }; - // transmission + this.setScissorTest = function ( boolean ) { - let _transmissionRenderTarget = null; + state.setScissorTest( _scissorTest = boolean ); - // camera matrices cache + }; - const _projScreenMatrix = new Matrix4(); + this.setOpaqueSort = function ( method ) { - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); + _opaqueSort = method; - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + }; - function getTargetPixelRatio() { + this.setTransparentSort = function ( method ) { - return _currentRenderTarget === null ? _pixelRatio : 1; + _transparentSort = method; - } + }; - // initialize + // Clearing - let _gl = _context; + this.getClearColor = function ( target ) { - function getContext( contextNames, contextAttributes ) { + return target.copy( background.getClearColor() ); - for ( let i = 0; i < contextNames.length; i ++ ) { + }; - const contextName = contextNames[ i ]; - const context = _canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; + this.setClearColor = function () { - } + background.setClearColor.apply( background, arguments ); - return null; + }; - } + this.getClearAlpha = function () { - try { + return background.getClearAlpha(); - const contextAttributes = { - alpha: true, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference, - failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat }; - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in _canvas ) _canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + this.setClearAlpha = function () { - // event listeners must be registered before WebGL context is created, see #12753 - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + background.setClearAlpha.apply( background, arguments ); - if ( _gl === null ) { + }; - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + this.clear = function ( color = true, depth = true, stencil = true ) { - if ( _this.isWebGL1Renderer === true ) { + let bits = 0; - contextNames.shift(); + if ( color ) { - } + // check if we're trying to clear an integer target + let isIntegerFormat = false; + if ( _currentRenderTarget !== null ) { - _gl = getContext( contextNames, contextAttributes ); + const targetFormat = _currentRenderTarget.texture.format; + isIntegerFormat = targetFormat === RGBAIntegerFormat || + targetFormat === RGIntegerFormat || + targetFormat === RedIntegerFormat; - if ( _gl === null ) { + } - if ( getContext( contextNames ) ) { + // use the appropriate clear functions to clear the target if it's a signed + // or unsigned integer target + if ( isIntegerFormat ) { - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + const targetType = _currentRenderTarget.texture.type; + const isUnsignedType = targetType === UnsignedByteType || + targetType === UnsignedIntType || + targetType === UnsignedShortType || + targetType === UnsignedInt248Type || + targetType === UnsignedShort4444Type || + targetType === UnsignedShort5551Type; - } else { + const clearColor = background.getClearColor(); + const a = background.getClearAlpha(); + const r = clearColor.r; + const g = clearColor.g; + const b = clearColor.b; - throw new Error( 'Error creating WebGL context.' ); + 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 ); - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + } - if ( _gl.getShaderPrecisionFormat === undefined ) { + } else { - _gl.getShaderPrecisionFormat = function () { + bits |= _gl.COLOR_BUFFER_BIT; - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + } - }; + } - } + if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil ) { - } catch ( error ) { + bits |= _gl.STENCIL_BUFFER_BIT; + this.state.buffers.stencil.setMask( 0xffffffff ); - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; + } - } + _gl.clear( bits ); - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; + }; - let background, morphtargets, bufferRenderer, indexedBufferRenderer; + this.clearColor = function () { - let utils, bindingStates, uniformsGroups; + this.clear( true, false, false ); - function initGLContext() { + }; - extensions = new WebGLExtensions( _gl ); + this.clearDepth = function () { - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + this.clear( false, true, false ); - extensions.init( capabilities ); + }; - utils = new WebGLUtils( _gl, extensions, capabilities ); + this.clearStencil = function () { - state = new WebGLState( _gl, extensions, capabilities ); + this.clear( false, false, true ); - info = new WebGLInfo(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, _premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); + }; - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); + // - info.programs = programCache.programs; + this.dispose = function () { - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; + canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - } + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + cubemaps.dispose(); + cubeuvmaps.dispose(); + objects.dispose(); + bindingStates.dispose(); + uniformsGroups.dispose(); + programCache.dispose(); - initGLContext(); + xr.dispose(); - // xr + xr.removeEventListener( 'sessionstart', onXRSessionStart ); + xr.removeEventListener( 'sessionend', onXRSessionEnd ); - const xr = new WebXRManager( _this, _gl ); + if ( _transmissionRenderTarget ) { - this.xr = xr; + _transmissionRenderTarget.dispose(); + _transmissionRenderTarget = null; - // API + } - this.getContext = function () { + animation.stop(); - return _gl; + }; - }; + // Events - this.getContextAttributes = function () { + function onContextLost( event ) { - return _gl.getContextAttributes(); + event.preventDefault(); - }; + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - this.forceContextLoss = function () { + _isContextLost = true; - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + } - }; + function onContextRestore( /* event */ ) { - this.forceContextRestore = function () { + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + _isContextLost = false; - }; + const infoAutoReset = info.autoReset; + const shadowMapEnabled = shadowMap.enabled; + const shadowMapAutoUpdate = shadowMap.autoUpdate; + const shadowMapNeedsUpdate = shadowMap.needsUpdate; + const shadowMapType = shadowMap.type; - this.getPixelRatio = function () { + initGLContext(); - return _pixelRatio; + info.autoReset = infoAutoReset; + shadowMap.enabled = shadowMapEnabled; + shadowMap.autoUpdate = shadowMapAutoUpdate; + shadowMap.needsUpdate = shadowMapNeedsUpdate; + shadowMap.type = shadowMapType; - }; + } - this.setPixelRatio = function ( value ) { + function onContextCreationError( event ) { - if ( value === undefined ) return; + console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); - _pixelRatio = value; + } - this.setSize( _width, _height, false ); + function onMaterialDispose( event ) { - }; + const material = event.target; - this.getSize = function ( target ) { + material.removeEventListener( 'dispose', onMaterialDispose ); - return target.set( _width, _height ); + deallocateMaterial( material ); - }; + } - this.setSize = function ( width, height, updateStyle ) { + // Buffer deallocation - if ( xr.isPresenting ) { + function deallocateMaterial( material ) { - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + releaseMaterialProgramReferences( material ); + + properties.remove( material ); } - _width = width; - _height = height; - _canvas.width = Math.floor( width * _pixelRatio ); - _canvas.height = Math.floor( height * _pixelRatio ); + function releaseMaterialProgramReferences( material ) { - if ( updateStyle !== false ) { + const programs = properties.get( material ).programs; - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + if ( programs !== undefined ) { - } + programs.forEach( function ( program ) { - this.setViewport( 0, 0, width, height ); + programCache.releaseProgram( program ); - }; + } ); - this.getDrawingBufferSize = function ( target ) { + if ( material.isShaderMaterial ) { - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); + programCache.releaseShaderCache( material ); - }; + } - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + } - _width = width; - _height = height; + } - _pixelRatio = pixelRatio; + // Buffer rendering - _canvas.width = Math.floor( width * pixelRatio ); - _canvas.height = Math.floor( height * pixelRatio ); + this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - this.setViewport( 0, 0, width, height ); + if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - }; + const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - this.getCurrentViewport = function ( target ) { + const program = setProgram( camera, scene, geometry, material, object ); - return target.copy( _currentViewport ); + state.setMaterial( material, frontFaceCW ); - }; + // - this.getViewport = function ( target ) { + let index = geometry.index; + let rangeFactor = 1; - return target.copy( _viewport ); + if ( material.wireframe === true ) { - }; + index = geometries.getWireframeAttribute( geometry ); - this.setViewport = function ( x, y, width, height ) { + if ( index === undefined ) return; - if ( x.isVector4 ) { + rangeFactor = 2; - _viewport.set( x.x, x.y, x.z, x.w ); + } - } else { + // - _viewport.set( x, y, width, height ); + const drawRange = geometry.drawRange; + const position = geometry.attributes.position; - } + let drawStart = drawRange.start * rangeFactor; + let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); + if ( group !== null ) { - }; + drawStart = Math.max( drawStart, group.start * rangeFactor ); + drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); - this.getScissor = function ( target ) { + } - return target.copy( _scissor ); + if ( index !== null ) { - }; + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, index.count ); - this.setScissor = function ( x, y, width, height ) { + } else if ( position !== undefined && position !== null ) { - if ( x.isVector4 ) { + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, position.count ); - _scissor.set( x.x, x.y, x.z, x.w ); + } - } else { + const drawCount = drawEnd - drawStart; - _scissor.set( x, y, width, height ); + if ( drawCount < 0 || drawCount === Infinity ) return; - } + // - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); + bindingStates.setup( object, material, program, geometry, index ); - }; + let attribute; + let renderer = bufferRenderer; - this.getScissorTest = function () { + if ( index !== null ) { - return _scissorTest; + attribute = attributes.get( index ); - }; + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); - this.setScissorTest = function ( boolean ) { + } - state.setScissorTest( _scissorTest = boolean ); + // - }; + if ( object.isMesh ) { - this.setOpaqueSort = function ( method ) { + if ( material.wireframe === true ) { - _opaqueSort = method; + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( _gl.LINES ); - }; + } else { - this.setTransparentSort = function ( method ) { + renderer.setMode( _gl.TRIANGLES ); - _transparentSort = method; + } - }; + } else if ( object.isLine ) { - // Clearing + let lineWidth = material.linewidth; - this.getClearColor = function ( target ) { + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - return target.copy( background.getClearColor() ); + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - }; + if ( object.isLineSegments ) { - this.setClearColor = function () { + renderer.setMode( _gl.LINES ); - background.setClearColor.apply( background, arguments ); + } else if ( object.isLineLoop ) { - }; + renderer.setMode( _gl.LINE_LOOP ); - this.getClearAlpha = function () { + } else { - return background.getClearAlpha(); + renderer.setMode( _gl.LINE_STRIP ); - }; + } - this.setClearAlpha = function () { + } else if ( object.isPoints ) { - background.setClearAlpha.apply( background, arguments ); + renderer.setMode( _gl.POINTS ); - }; + } else if ( object.isSprite ) { - this.clear = function ( color = true, depth = true, stencil = true ) { + renderer.setMode( _gl.TRIANGLES ); - let bits = 0; + } - if ( color ) bits |= 16384; - if ( depth ) bits |= 256; - if ( stencil ) bits |= 1024; + if ( object.isBatchedMesh ) { - _gl.clear( bits ); + renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); - }; + } else if ( object.isInstancedMesh ) { - this.clearColor = function () { + renderer.renderInstances( drawStart, drawCount, object.count ); - this.clear( true, false, false ); + } else if ( geometry.isInstancedBufferGeometry ) { - }; + const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; + const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); - this.clearDepth = function () { + renderer.renderInstances( drawStart, drawCount, instanceCount ); - this.clear( false, true, false ); + } else { - }; + renderer.render( drawStart, drawCount ); - this.clearStencil = function () { + } - this.clear( false, false, true ); + }; - }; + // Compile - // + function prepareMaterial( material, scene, object ) { - this.dispose = function () { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + material.side = BackSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); + material.side = FrontSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - xr.dispose(); + material.side = DoubleSide; - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); + } else { - if ( _transmissionRenderTarget ) { + getProgram( material, scene, object ); - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; + } } - animation.stop(); + this.compile = function ( scene, camera, targetScene = null ) { - }; + if ( targetScene === null ) targetScene = scene; - // Events + currentRenderState = renderStates.get( targetScene ); + currentRenderState.init(); - function onContextLost( event ) { + renderStateStack.push( currentRenderState ); - event.preventDefault(); + // gather lights from both the target scene and the new object that will be added to the scene. - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + targetScene.traverseVisible( function ( object ) { - _isContextLost = true; + if ( object.isLight && object.layers.test( camera.layers ) ) { - } + currentRenderState.pushLight( object ); - function onContextRestore( /* event */ ) { + if ( object.castShadow ) { - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + currentRenderState.pushShadow( object ); - _isContextLost = false; + } - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; + } - initGLContext(); + } ); - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; + if ( scene !== targetScene ) { - } + scene.traverseVisible( function ( object ) { - function onContextCreationError( event ) { + if ( object.isLight && object.layers.test( camera.layers ) ) { - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); + currentRenderState.pushLight( object ); - } + if ( object.castShadow ) { - function onMaterialDispose( event ) { + currentRenderState.pushShadow( object ); - const material = event.target; + } - material.removeEventListener( 'dispose', onMaterialDispose ); + } - deallocateMaterial( material ); + } ); - } + } - // Buffer deallocation + currentRenderState.setupLights( _this._useLegacyLights ); - function deallocateMaterial( material ) { + // Only initialize materials in the new scene, not the targetScene. - releaseMaterialProgramReferences( material ); + const materials = new Set(); - properties.remove( material ); + scene.traverse( function ( object ) { - } + const material = object.material; + if ( material ) { - function releaseMaterialProgramReferences( material ) { + if ( Array.isArray( material ) ) { - const programs = properties.get( material ).programs; + for ( let i = 0; i < material.length; i ++ ) { - if ( programs !== undefined ) { + const material2 = material[ i ]; - programs.forEach( function ( program ) { + prepareMaterial( material2, targetScene, object ); + materials.add( material2 ); - programCache.releaseProgram( program ); + } - } ); + } else { - if ( material.isShaderMaterial ) { + prepareMaterial( material, targetScene, object ); + materials.add( material ); - programCache.releaseShaderCache( material ); + } - } + } - } + } ); - } + renderStateStack.pop(); + currentRenderState = null; - // Buffer rendering + return materials; - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { + }; - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) + // compileAsync - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + this.compileAsync = function ( scene, camera, targetScene = null ) { - const program = setProgram( camera, scene, geometry, material, object ); + const materials = this.compile( scene, camera, targetScene ); - state.setMaterial( material, frontFaceCW ); + // Wait for all the materials in the new object to indicate that they're + // ready to be used before resolving the promise. - // + return new Promise( ( resolve ) => { - let index = geometry.index; - let rangeFactor = 1; + function checkMaterialsReady() { - if ( material.wireframe === true ) { + materials.forEach( function ( material ) { - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + const materialProperties = properties.get( material ); + const program = materialProperties.currentProgram; - } + if ( program.isReady() ) { - // + // remove any programs that report they're ready to use from the list + materials.delete( material ); - const drawRange = geometry.drawRange; - const position = geometry.attributes.position; + } + + } ); - let drawStart = drawRange.start * rangeFactor; - let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; + // once the list of compiling materials is empty, call the callback - if ( group !== null ) { + if ( materials.size === 0 ) { - drawStart = Math.max( drawStart, group.start * rangeFactor ); - drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); + resolve( scene ); + return; - } + } - if ( index !== null ) { + // if some materials are still not ready, wait a bit and check again - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, index.count ); + setTimeout( checkMaterialsReady, 10 ); - } else if ( position !== undefined && position !== null ) { + } - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, position.count ); + if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { - } + // If we can check the compilation status of the materials without + // blocking then do so right away. - const drawCount = drawEnd - drawStart; + checkMaterialsReady(); - if ( drawCount < 0 || drawCount === Infinity ) return; + } else { - // + // Otherwise start by waiting a bit to give the materials we just + // initialized a chance to finish. - bindingStates.setup( object, material, program, geometry, index ); + setTimeout( checkMaterialsReady, 10 ); - let attribute; - let renderer = bufferRenderer; + } - if ( index !== null ) { + } ); - attribute = attributes.get( index ); + }; - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + // Animation Loop - } + let onAnimationFrameCallback = null; - // + function onAnimationFrame( time ) { - if ( object.isMesh ) { + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - if ( material.wireframe === true ) { + } - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); + function onXRSessionStart() { - } else { + animation.stop(); - renderer.setMode( 4 ); + } - } + function onXRSessionEnd() { - } else if ( object.isLine ) { + animation.start(); - let lineWidth = material.linewidth; + } - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + const animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + if ( typeof self !== 'undefined' ) animation.setContext( self ); - if ( object.isLineSegments ) { + this.setAnimationLoop = function ( callback ) { - renderer.setMode( 1 ); + onAnimationFrameCallback = callback; + xr.setAnimationLoop( callback ); - } else if ( object.isLineLoop ) { + ( callback === null ) ? animation.stop() : animation.start(); - renderer.setMode( 2 ); + }; - } else { + xr.addEventListener( 'sessionstart', onXRSessionStart ); + xr.addEventListener( 'sessionend', onXRSessionEnd ); - renderer.setMode( 3 ); + // Rendering - } + this.render = function ( scene, camera ) { - } else if ( object.isPoints ) { + if ( camera !== undefined && camera.isCamera !== true ) { - renderer.setMode( 0 ); + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - } else if ( object.isSprite ) { + } - renderer.setMode( 4 ); + if ( _isContextLost === true ) return; - } + // update scene graph - if ( object.isInstancedMesh ) { + if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - renderer.renderInstances( drawStart, drawCount, object.count ); + // update camera matrices and frustum - } else if ( geometry.isInstancedBufferGeometry ) { + if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; - const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); + if ( xr.enabled === true && xr.isPresenting === true ) { - renderer.renderInstances( drawStart, drawCount, instanceCount ); + if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - } else { + camera = xr.getCamera(); // use XR camera for rendering - renderer.render( drawStart, drawCount ); + } - } + // + if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - }; + currentRenderState = renderStates.get( scene, renderStateStack.length ); + currentRenderState.init(); - // Compile + renderStateStack.push( currentRenderState ); - this.compile = function ( scene, camera ) { + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix ); - function prepare( material, scene, object ) { + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); - if ( material.transparent === true && material.side === DoubleSide ) { + currentRenderList = renderLists.get( scene, renderListStack.length ); + currentRenderList.init(); - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + renderListStack.push( currentRenderList ); - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + projectObject( scene, camera, 0, _this.sortObjects ); - material.side = DoubleSide; + currentRenderList.finish(); - } else { + if ( _this.sortObjects === true ) { - getProgram( material, scene, object ); + currentRenderList.sort( _opaqueSort, _transparentSort ); } - } + // - currentRenderState = renderStates.get( scene ); - currentRenderState.init(); + this.info.render.frame ++; - renderStateStack.push( currentRenderState ); + if ( _clippingEnabled === true ) clipping.beginShadows(); - scene.traverseVisible( function ( object ) { + const shadowsArray = currentRenderState.state.shadowsArray; - if ( object.isLight && object.layers.test( camera.layers ) ) { + shadowMap.render( shadowsArray, scene, camera ); - currentRenderState.pushLight( object ); + if ( _clippingEnabled === true ) clipping.endShadows(); - if ( object.castShadow ) { + // - currentRenderState.pushShadow( object ); + if ( this.info.autoReset === true ) this.info.reset(); - } - } + // - } ); + background.render( currentRenderList, scene ); - currentRenderState.setupLights( _this.physicallyCorrectLights ); + // render scene - scene.traverse( function ( object ) { + currentRenderState.setupLights( _this._useLegacyLights ); - const material = object.material; + if ( camera.isArrayCamera ) { - if ( material ) { + const cameras = camera.cameras; - if ( Array.isArray( material ) ) { + for ( let i = 0, l = cameras.length; i < l; i ++ ) { - for ( let i = 0; i < material.length; i ++ ) { + const camera2 = cameras[ i ]; - const material2 = material[ i ]; + renderScene( currentRenderList, scene, camera2, camera2.viewport ); - prepare( material2, scene, object ); + } - } + } else { - } else { + renderScene( currentRenderList, scene, camera ); - prepare( material, scene, object ); + } - } + // - } + if ( _currentRenderTarget !== null ) { - } ); + // resolve multisample renderbuffers to a single-sample texture if necessary - renderStateStack.pop(); - currentRenderState = null; + textures.updateMultisampleRenderTarget( _currentRenderTarget ); - }; + // Generate mipmap if we're using any kind of mipmap filtering - // Animation Loop + textures.updateRenderTargetMipmap( _currentRenderTarget ); + + } - let onAnimationFrameCallback = null; + // - function onAnimationFrame( time ) { + if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + // _gl.finish(); - } + bindingStates.resetDefaultState(); + _currentMaterialId = - 1; + _currentCamera = null; - function onXRSessionStart() { + renderStateStack.pop(); - animation.stop(); + if ( renderStateStack.length > 0 ) { - } + currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - function onXRSessionEnd() { + } else { - animation.start(); + currentRenderState = null; - } + } - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + renderListStack.pop(); - if ( typeof self !== 'undefined' ) animation.setContext( self ); + if ( renderListStack.length > 0 ) { - this.setAnimationLoop = function ( callback ) { + currentRenderList = renderListStack[ renderListStack.length - 1 ]; - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); + } else { - ( callback === null ) ? animation.stop() : animation.start(); + currentRenderList = null; - }; + } - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); + }; - // Rendering + function projectObject( object, camera, groupOrder, sortObjects ) { - this.render = function ( scene, camera ) { + if ( object.visible === false ) return; - if ( camera !== undefined && camera.isCamera !== true ) { + const visible = object.layers.test( camera.layers ); - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + if ( visible ) { - } + if ( object.isGroup ) { - if ( _isContextLost === true ) return; + groupOrder = object.renderOrder; - // update scene graph + } else if ( object.isLOD ) { - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); + if ( object.autoUpdate === true ) object.update( camera ); - // update camera matrices and frustum + } else if ( object.isLight ) { - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); + currentRenderState.pushLight( object ); - if ( xr.enabled === true && xr.isPresenting === true ) { + if ( object.castShadow ) { - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); + currentRenderState.pushShadow( object ); - camera = xr.getCamera(); // use XR camera for rendering + } - } + } else if ( object.isSprite ) { - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); + if ( sortObjects ) { - renderStateStack.push( currentRenderState ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); + } - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + const geometry = objects.update( object ); + const material = object.material; - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); + if ( material.visible ) { - renderListStack.push( currentRenderList ); + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - projectObject( scene, camera, 0, _this.sortObjects ); + } - currentRenderList.finish(); + } - if ( _this.sortObjects === true ) { + } else if ( object.isMesh || object.isLine || object.isPoints ) { - currentRenderList.sort( _opaqueSort, _transparentSort ); + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - } + const geometry = objects.update( object ); + const material = object.material; - // + if ( sortObjects ) { - if ( _clippingEnabled === true ) clipping.beginShadows(); + if ( object.boundingSphere !== undefined ) { - const shadowsArray = currentRenderState.state.shadowsArray; + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + _vector3.copy( object.boundingSphere.center ); - shadowMap.render( shadowsArray, scene, camera ); + } else { - if ( _clippingEnabled === true ) clipping.endShadows(); + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + _vector3.copy( geometry.boundingSphere.center ); - // + } - if ( this.info.autoReset === true ) this.info.reset(); + _vector3 + .applyMatrix4( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - // + } - background.render( currentRenderList, scene ); + if ( Array.isArray( material ) ) { - // render scene + const groups = geometry.groups; - currentRenderState.setupLights( _this.physicallyCorrectLights ); + for ( let i = 0, l = groups.length; i < l; i ++ ) { - if ( camera.isArrayCamera ) { + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - const cameras = camera.cameras; + if ( groupMaterial && groupMaterial.visible ) { - for ( let i = 0, l = cameras.length; i < l; i ++ ) { + currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - const camera2 = cameras[ i ]; + } - renderScene( currentRenderList, scene, camera2, camera2.viewport ); + } - } + } else if ( material.visible ) { - } else { + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - renderScene( currentRenderList, scene, camera ); + } - } + } - // + } - if ( _currentRenderTarget !== null ) { + } - // resolve multisample renderbuffers to a single-sample texture if necessary + const children = object.children; - textures.updateMultisampleRenderTarget( _currentRenderTarget ); + for ( let i = 0, l = children.length; i < l; i ++ ) { - // Generate mipmap if we're using any kind of mipmap filtering + projectObject( children[ i ], camera, groupOrder, sortObjects ); - textures.updateRenderTargetMipmap( _currentRenderTarget ); + } } - // + function renderScene( currentRenderList, scene, camera, viewport ) { - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); + const opaqueObjects = currentRenderList.opaque; + const transmissiveObjects = currentRenderList.transmissive; + const transparentObjects = currentRenderList.transparent; - // _gl.finish(); + currentRenderState.setupLightsView( camera ); - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; + if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); - renderStateStack.pop(); + if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); - if ( renderStateStack.length > 0 ) { + if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; + if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); + if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); + if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - } else { + // Ensure depth buffer writing is enabled so it can be cleared on next render - currentRenderState = null; + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); - } + state.setPolygonOffset( false ); - renderListStack.pop(); + } - if ( renderListStack.length > 0 ) { + function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { - currentRenderList = renderListStack[ renderListStack.length - 1 ]; + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } else { + if ( overrideMaterial !== null ) { - currentRenderList = null; + return; - } + } - }; + const isWebGL2 = capabilities.isWebGL2; - function projectObject( object, camera, groupOrder, sortObjects ) { + if ( _transmissionRenderTarget === null ) { - if ( object.visible === false ) return; + _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { + generateMipmaps: true, + type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, + minFilter: LinearMipmapLinearFilter, + samples: ( isWebGL2 ) ? 4 : 0 + } ); - const visible = object.layers.test( camera.layers ); + // debug - if ( visible ) { + /* + const geometry = new PlaneGeometry(); + const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); - if ( object.isGroup ) { + const mesh = new Mesh( geometry, material ); + scene.add( mesh ); + */ - groupOrder = object.renderOrder; + } - } else if ( object.isLOD ) { + _this.getDrawingBufferSize( _vector2 ); - if ( object.autoUpdate === true ) object.update( camera ); + if ( isWebGL2 ) { - } else if ( object.isLight ) { + _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - currentRenderState.pushLight( object ); + } else { - if ( object.castShadow ) { + _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - currentRenderState.pushShadow( object ); + } - } + // - } else if ( object.isSprite ) { + const currentRenderTarget = _this.getRenderTarget(); + _this.setRenderTarget( _transmissionRenderTarget ); - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + _this.getClearColor( _currentClearColor ); + _currentClearAlpha = _this.getClearAlpha(); + if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); - if ( sortObjects ) { + _this.clear(); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + // 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; - } + renderObjects( opaqueObjects, scene, camera ); - const geometry = objects.update( object ); - const material = object.material; + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - if ( material.visible ) { + let renderTargetNeedsUpdate = false; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { - } + const renderItem = transmissiveObjects[ i ]; - } + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = renderItem.material; + const group = renderItem.group; - } else if ( object.isMesh || object.isLine || object.isPoints ) { + if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { - if ( object.isSkinnedMesh ) { + const currentSide = material.side; - // update skeleton only once in a frame + material.side = BackSide; + material.needsUpdate = true; - if ( object.skeleton.frame !== info.render.frame ) { + renderObject( object, scene, camera, geometry, material, group ); - object.skeleton.update(); - object.skeleton.frame = info.render.frame; + material.side = currentSide; + material.needsUpdate = true; - } + renderTargetNeedsUpdate = true; } - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - if ( sortObjects ) { + } - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + if ( renderTargetNeedsUpdate === true ) { - } + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - const geometry = objects.update( object ); - const material = object.material; + } - if ( Array.isArray( material ) ) { + _this.setRenderTarget( currentRenderTarget ); - const groups = geometry.groups; + _this.setClearColor( _currentClearColor, _currentClearAlpha ); - for ( let i = 0, l = groups.length; i < l; i ++ ) { + _this.toneMapping = currentToneMapping; - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; + } - if ( groupMaterial && groupMaterial.visible ) { + function renderObjects( renderList, scene, camera ) { - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } + for ( let i = 0, l = renderList.length; i < l; i ++ ) { - } + const renderItem = renderList[ i ]; - } else if ( material.visible ) { + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = overrideMaterial === null ? renderItem.material : overrideMaterial; + const group = renderItem.group; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + if ( object.layers.test( camera.layers ) ) { - } + renderObject( object, scene, camera, geometry, material, group ); } @@ -27609,1059 +29389,1045 @@ } - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + function renderObject( object, scene, camera, geometry, material, group ) { - projectObject( children[ i ], camera, groupOrder, sortObjects ); + object.onBeforeRender( _this, scene, camera, geometry, material, group ); - } + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - } + material.onBeforeRender( _this, scene, camera, geometry, object, group ); - function renderScene( currentRenderList, scene, camera, viewport ) { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; + material.side = BackSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - currentRenderState.setupLightsView( camera ); + material.side = FrontSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); + material.side = DoubleSide; - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); + } else { - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - // Ensure depth buffer writing is enabled so it can be cleared on next render + } - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + object.onAfterRender( _this, scene, camera, geometry, material, group ); - state.setPolygonOffset( false ); + } - } + function getProgram( material, scene, object ) { - function renderTransmissionPass( opaqueObjects, scene, camera ) { + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - const isWebGL2 = capabilities.isWebGL2; + const materialProperties = properties.get( material ); - if ( _transmissionRenderTarget === null ) { + const lights = currentRenderState.state.lights; + const shadowsArray = currentRenderState.state.shadowsArray; - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 && _antialias === true ) ? 4 : 0 - } ); + const lightsStateVersion = lights.state.version; - } + const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); + const programCacheKey = programCache.getProgramCacheKey( parameters ); - _this.getDrawingBufferSize( _vector2 ); + let programs = materialProperties.programs; - if ( isWebGL2 ) { + // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); + materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; + materialProperties.fog = scene.fog; + materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - } else { + if ( programs === undefined ) { - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); + // new material - } + material.addEventListener( 'dispose', onMaterialDispose ); - // + programs = new Map(); + materialProperties.programs = programs; - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - _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; + let program = programs.get( programCacheKey ); - renderObjects( opaqueObjects, scene, camera ); + if ( program !== undefined ) { - _this.toneMapping = currentToneMapping; + // early out if program and light state is identical - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); + if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - _this.setRenderTarget( currentRenderTarget ); + updateCommonMaterialProperties( material, parameters ); - } + return program; - function renderObjects( renderList, scene, camera ) { + } - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; + } else { - for ( let i = 0, l = renderList.length; i < l; i ++ ) { + parameters.uniforms = programCache.getUniforms( material ); - const renderItem = renderList[ i ]; + material.onBuild( object, parameters, _this ); - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; + material.onBeforeCompile( parameters, _this ); - if ( object.layers.test( camera.layers ) ) { + program = programCache.acquireProgram( parameters, programCacheKey ); + programs.set( programCacheKey, program ); - renderObject( object, scene, camera, geometry, material, group ); + materialProperties.uniforms = parameters.uniforms; } - } - - } + const uniforms = materialProperties.uniforms; - function renderObject( object, scene, camera, geometry, material, group ) { + if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - object.onBeforeRender( _this, scene, camera, geometry, material, group ); + uniforms.clippingPlanes = clipping.uniform; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + } - material.onBeforeRender( _this, scene, camera, geometry, object, group ); + updateCommonMaterialProperties( material, parameters ); - if ( material.transparent === true && material.side === DoubleSide ) { + // store the light setup it was created for - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + materialProperties.needsLights = materialNeedsLights( material ); + materialProperties.lightsStateVersion = lightsStateVersion; - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + if ( materialProperties.needsLights ) { - material.side = DoubleSide; + // wire up the material to this renderer's lighting state - } else { + 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; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + 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 - } + } - object.onAfterRender( _this, scene, camera, geometry, material, group ); + materialProperties.currentProgram = program; + materialProperties.uniformsList = null; - } + return program; - function getProgram( material, scene, object ) { + } - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + function getUniformList( materialProperties ) { - const materialProperties = properties.get( material ); + if ( materialProperties.uniformsList === null ) { - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; + const progUniforms = materialProperties.currentProgram.getUniforms(); + materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); - const lightsStateVersion = lights.state.version; + } - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); + return materialProperties.uniformsList; - let programs = materialProperties.programs; + } - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change + function updateCommonMaterialProperties( material, parameters ) { - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); + const materialProperties = properties.get( material ); - if ( programs === undefined ) { + materialProperties.outputColorSpace = parameters.outputColorSpace; + materialProperties.batching = parameters.batching; + materialProperties.instancing = parameters.instancing; + materialProperties.instancingColor = parameters.instancingColor; + 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; - // new material + } - material.addEventListener( 'dispose', onMaterialDispose ); + function setProgram( camera, scene, geometry, material, object ) { - programs = new Map(); - materialProperties.programs = programs; + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - } + textures.resetTextureUnits(); - let program = programs.get( programCacheKey ); + const fog = scene.fog; + const environment = material.isMeshStandardMaterial ? scene.environment : null; + const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); + const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); + const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; + const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); + const morphTargets = !! geometry.morphAttributes.position; + const morphNormals = !! geometry.morphAttributes.normal; + const morphColors = !! geometry.morphAttributes.color; - if ( program !== undefined ) { + let toneMapping = NoToneMapping; - // early out if program and light state is identical + if ( material.toneMapped ) { - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { + if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { - updateCommonMaterialProperties( material, parameters ); + toneMapping = _this.toneMapping; - return program; + } } - } else { + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - parameters.uniforms = programCache.getUniforms( material ); + const materialProperties = properties.get( material ); + const lights = currentRenderState.state.lights; - material.onBuild( object, parameters, _this ); + if ( _clippingEnabled === true ) { - material.onBeforeCompile( parameters, _this ); + if ( _localClippingEnabled === true || camera !== _currentCamera ) { - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); + const useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - materialProperties.uniforms = parameters.uniforms; + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + clipping.setState( material, camera, useCache ); - } + } - const uniforms = materialProperties.uniforms; + } - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { + // - uniforms.clippingPlanes = clipping.uniform; + let needsProgramChange = false; - } + if ( material.version === materialProperties.__version ) { - updateCommonMaterialProperties( material, parameters ); + if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - // store the light setup it was created for + needsProgramChange = true; - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; + } else if ( materialProperties.outputColorSpace !== colorSpace ) { - if ( materialProperties.needsLights ) { + needsProgramChange = true; - // wire up the material to this renderer's lighting state + } else if ( object.isBatchedMesh && materialProperties.batching === false ) { - 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; + needsProgramChange = true; - 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 + } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { - } + needsProgramChange = true; - const progUniforms = program.getUniforms(); - const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - materialProperties.currentProgram = program; - materialProperties.uniformsList = uniformsList; + needsProgramChange = true; - return program; + } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - } + needsProgramChange = true; - function updateCommonMaterialProperties( material, parameters ) { + } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - const materialProperties = properties.get( material ); + needsProgramChange = true; - materialProperties.outputEncoding = parameters.outputEncoding; - materialProperties.instancing = parameters.instancing; - 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; + } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - } + needsProgramChange = true; - function setProgram( camera, scene, geometry, material, object ) { + } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + needsProgramChange = true; - textures.resetTextureUnits(); + } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.encoding : LinearEncoding ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent; - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; + needsProgramChange = true; - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + } else if ( materialProperties.envMap !== envMap ) { - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; + needsProgramChange = true; - if ( _clippingEnabled === true ) { + } else if ( material.fog === true && materialProperties.fog !== fog ) { - if ( _localClippingEnabled === true || camera !== _currentCamera ) { + needsProgramChange = true; - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== clipping.numPlanes || + materialProperties.numIntersection !== clipping.numIntersection ) ) { - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); + needsProgramChange = true; - } + } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - } + needsProgramChange = true; - // + } else if ( materialProperties.vertexTangents !== vertexTangents ) { - let needsProgramChange = false; + needsProgramChange = true; - if ( material.version === materialProperties.__version ) { + } else if ( materialProperties.morphTargets !== morphTargets ) { - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphNormals !== morphNormals ) { - } else if ( materialProperties.outputEncoding !== encoding ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphColors !== morphColors ) { - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.toneMapping !== toneMapping ) { - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { + needsProgramChange = true; - needsProgramChange = true; + } - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { + } else { needsProgramChange = true; + materialProperties.__version = material.version; - } else if ( materialProperties.envMap !== envMap ) { + } - needsProgramChange = true; + // - } else if ( material.fog === true && materialProperties.fog !== fog ) { + let program = materialProperties.currentProgram; - needsProgramChange = true; + if ( needsProgramChange === true ) { - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { + program = getProgram( material, scene, object ); - needsProgramChange = true; + } - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { + let refreshProgram = false; + let refreshMaterial = false; + let refreshLights = false; - needsProgramChange = true; + const p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.uniforms; - } else if ( materialProperties.vertexTangents !== vertexTangents ) { + if ( state.useProgram( program.program ) ) { - needsProgramChange = true; + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - } else if ( materialProperties.morphTargets !== morphTargets ) { + } - needsProgramChange = true; + if ( material.id !== _currentMaterialId ) { - } else if ( materialProperties.morphNormals !== morphNormals ) { + _currentMaterialId = material.id; - needsProgramChange = true; + refreshMaterial = true; - } else if ( materialProperties.morphColors !== morphColors ) { + } - needsProgramChange = true; + if ( refreshProgram || _currentCamera !== camera ) { - } else if ( materialProperties.toneMapping !== toneMapping ) { + // common camera uniforms - needsProgramChange = true; + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { + const uCamPos = p_uniforms.map.cameraPosition; - needsProgramChange = true; + if ( uCamPos !== undefined ) { - } + uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - } else { + } - needsProgramChange = true; - materialProperties.__version = material.version; + if ( capabilities.logarithmicDepthBuffer ) { - } + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - // + } - let program = materialProperties.currentProgram; + // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 - if ( needsProgramChange === true ) { + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial ) { - program = getProgram( material, scene, object ); + p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - } + } - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; + if ( _currentCamera !== camera ) { - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; + _currentCamera = camera; - if ( state.useProgram( program.program ) ) { + // lighting uniforms depend on the camera so enforce an update + // now, in case this material supports lights - or later, when + // the next material that does gets activated: - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - } + } - if ( material.id !== _currentMaterialId ) { + } - _currentMaterialId = material.id; + // skinning and morph target uniforms must be set even if material didn't change + // auto-setting of texture unit for bone and morph texture must go before other textures + // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - refreshMaterial = true; + if ( object.isSkinnedMesh ) { - } + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - if ( refreshProgram || _currentCamera !== camera ) { + const skeleton = object.skeleton; - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( skeleton ) { - if ( capabilities.logarithmicDepthBuffer ) { + if ( capabilities.floatVertexTextures ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - } + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - if ( _currentCamera !== camera ) { + } else { - _currentCamera = camera; + console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: + } - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + } } - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + if ( object.isBatchedMesh ) { - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshStandardMaterial || - material.envMap ) { + p_uniforms.setOptional( _gl, object, 'batchingTexture' ); + p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); - const uCamPos = p_uniforms.map.cameraPosition; + } - if ( uCamPos !== undefined ) { + const morphAttributes = geometry.morphAttributes; - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - } + morphtargets.update( object, geometry, program ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { + if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); + materialProperties.receiveShadow = object.receiveShadow; + p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.isShadowMaterial || - object.isSkinnedMesh ) { + // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - } + m_uniforms.envMap.value = envMap; - } + m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures + } - if ( object.isSkinnedMesh ) { + if ( refreshMaterial ) { - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - const skeleton = object.skeleton; + if ( materialProperties.needsLights ) { + + // the current material requires lighting info - if ( skeleton ) { + // note: all lighting uniforms are always set correctly + // they simply reference the renderer's state for their + // values + // + // use the current material's .needsUpdate flags to set + // the GL state when required - if ( capabilities.floatVertexTextures ) { + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); + } - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + // refresh uniforms common to several materials - } else { + if ( fog && material.fog === true ) { - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); + materials.refreshFogUniforms( m_uniforms, fog ); } + materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + } - } + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - const morphAttributes = geometry.morphAttributes; + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + material.uniformsNeedUpdate = false; - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { + } - morphtargets.update( object, geometry, material, program ); + if ( material.isSpriteMaterial ) { - } + p_uniforms.setValue( _gl, 'center', object.center ); - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { + } - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); + // common matrices - } + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 + // UBOs - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { + if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - m_uniforms.envMap.value = envMap; + const groups = material.uniformsGroups; - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + for ( let i = 0, l = groups.length; i < l; i ++ ) { - } + if ( capabilities.isWebGL2 ) { - if ( refreshMaterial ) { + const group = groups[ i ]; - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + uniformsGroups.update( group, program ); + uniformsGroups.bind( group, program ); - if ( materialProperties.needsLights ) { + } else { - // the current material requires lighting info + console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required + } - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + } } - // refresh uniforms common to several materials + return program; - if ( fog && material.fog === true ) { + } - materials.refreshFogUniforms( m_uniforms, fog ); + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - } + function markUniformsLightsNeedsUpdate( uniforms, value ) { - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + uniforms.ambientLightColor.needsUpdate = value; + uniforms.lightProbe.needsUpdate = value; - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + 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; } - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + function materialNeedsLights( material ) { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - material.uniformsNeedUpdate = false; + return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || + material.isMeshStandardMaterial || material.isShadowMaterial || + ( material.isShaderMaterial && material.lights === true ); } - if ( material.isSpriteMaterial ) { + this.getActiveCubeFace = function () { - p_uniforms.setValue( _gl, 'center', object.center ); + return _currentActiveCubeFace; - } + }; - // common matrices + this.getActiveMipmapLevel = function () { - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); + return _currentActiveMipmapLevel; - // UBOs + }; + + this.getRenderTarget = function () { - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { + return _currentRenderTarget; - const groups = material.uniformsGroups; + }; - for ( let i = 0, l = groups.length; i < l; i ++ ) { + this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - if ( capabilities.isWebGL2 ) { + properties.get( renderTarget.texture ).__webglTexture = colorTexture; + properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - const group = groups[ i ]; + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__hasExternalTextures = true; - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); + if ( renderTargetProperties.__hasExternalTextures ) { - } else { + renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; + + if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + + // The multisample_render_to_texture extension doesn't work properly if there + // are midframe flushes and an external depth buffer. Disable use of the extension. + if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); + console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); + renderTargetProperties.__useRenderToTexture = false; + + } } } - } + }; - return program; + this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - } + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__webglFramebuffer = defaultFramebuffer; + renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + }; - function markUniformsLightsNeedsUpdate( uniforms, value ) { + this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; + _currentRenderTarget = renderTarget; + _currentActiveCubeFace = activeCubeFace; + _currentActiveMipmapLevel = activeMipmapLevel; - 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; + let useDefaultFramebuffer = true; + let framebuffer = null; + let isCube = false; + let isRenderTarget3D = false; - } + if ( renderTarget ) { - function materialNeedsLights( material ) { + const renderTargetProperties = properties.get( renderTarget ); - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); + if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - } + // We need to make sure to rebind the framebuffer. + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); + useDefaultFramebuffer = false; - this.getActiveCubeFace = function () { + } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - return _currentActiveCubeFace; + textures.setupRenderTarget( renderTarget ); - }; + } else if ( renderTargetProperties.__hasExternalTextures ) { - this.getActiveMipmapLevel = function () { + // Color and depth texture must be rebound in order for the swapchain to update. + textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - return _currentActiveMipmapLevel; + } - }; + const texture = renderTarget.texture; - this.getRenderTarget = function () { + if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - return _currentRenderTarget; + isRenderTarget3D = true; - }; + } - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { + const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; + if ( renderTarget.isWebGLCubeRenderTarget ) { - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; + if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { - if ( renderTargetProperties.__hasExternalTextures ) { + framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; + } else { - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + framebuffer = __webglFramebuffer[ activeCubeFace ]; - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { + } - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; + isCube = true; - } + } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - } + framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - } + } else { - }; + if ( Array.isArray( __webglFramebuffer ) ) { - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { + framebuffer = __webglFramebuffer[ activeMipmapLevel ]; - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; + } else { - }; + framebuffer = __webglFramebuffer; - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { + } - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; + } - let useDefaultFramebuffer = true; - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - if ( renderTarget ) { + } else { - const renderTargetProperties = properties.get( renderTarget ); + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); + _currentScissorTest = _scissorTest; - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { + } - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( 36160, null ); - useDefaultFramebuffer = false; + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { + if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - textures.setupRenderTarget( renderTarget ); + state.drawBuffers( renderTarget, framebuffer ); - } else if ( renderTargetProperties.__hasExternalTextures ) { + } - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - } + if ( isCube ) { - const texture = renderTarget.texture; + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + } else if ( isRenderTarget3D ) { - isRenderTarget3D = true; + const textureProperties = properties.get( renderTarget.texture ); + const layer = activeCubeFace || 0; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); } - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings - if ( renderTarget.isWebGLCubeRenderTarget ) { + }; - framebuffer = __webglFramebuffer[ activeCubeFace ]; - isCube = true; + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } else { + } - framebuffer = __webglFramebuffer; + let framebuffer = properties.get( renderTarget ).__webglFramebuffer; + + if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { + + framebuffer = framebuffer[ activeCubeFaceIndex ]; } - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + if ( framebuffer ) { - } else { + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; + try { - } + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - state.drawBuffers( renderTarget, framebuffer ); + } - } + const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! halfFloatSupportedByExt ) { - if ( isCube ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); + } - } else if ( isRenderTarget3D ) { + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - } + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + } - }; + } finally { - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { + // restore framebuffer of current render target if necessary - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + } - } + } - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; + }; - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { + this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - framebuffer = framebuffer[ activeCubeFaceIndex ]; + const levelScale = Math.pow( 2, - level ); + const width = Math.floor( texture.image.width * levelScale ); + const height = Math.floor( texture.image.height * levelScale ); - } + textures.setTexture2D( texture, 0 ); - if ( framebuffer ) { + _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); - state.bindFramebuffer( 36160, framebuffer ); + state.unbindTexture(); - try { + }; - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { + const width = srcTexture.image.width; + const height = srcTexture.image.height; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + textures.setTexture2D( dstTexture, 0 ); - } + // As another texture upload may have changed pixelStorei + // parameters, make sure they are correct for the dstTexture + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); + if ( srcTexture.isDataTexture ) { - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + } else { - } + if ( srcTexture.isCompressedTexture ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + } else { - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); } - } finally { - - // restore framebuffer of current render target if necessary + } - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( 36160, framebuffer ); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); - } + state.unbindTexture(); - } + }; - }; + this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { + if ( _this.isWebGL1Renderer ) { - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); + return; - textures.setTexture2D( texture, 0 ); + } - _gl.copyTexSubImage2D( 3553, level, 0, 0, position.x, position.y, width, height ); + const width = sourceBox.max.x - sourceBox.min.x + 1; + const height = sourceBox.max.y - sourceBox.min.y + 1; + const depth = sourceBox.max.z - sourceBox.min.z + 1; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); + let glTarget; - state.unbindTexture(); + if ( dstTexture.isData3DTexture ) { - }; + textures.setTexture3D( dstTexture, 0 ); + glTarget = _gl.TEXTURE_3D; - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { + } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); + textures.setTexture2DArray( dstTexture, 0 ); + glTarget = _gl.TEXTURE_2D_ARRAY; - textures.setTexture2D( dstTexture, 0 ); + } else { - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); + return; - if ( srcTexture.isDataTexture ) { + } - _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - } else { + const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); + const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); + const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); + const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); + const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); - if ( srcTexture.isCompressedTexture ) { + const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; - _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); - } else { + if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - } + } else { - } + if ( srcTexture.isCompressedArrayTexture ) { - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); + _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - state.unbindTexture(); + } else { - }; + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { + } - if ( _this.isWebGL1Renderer ) { + } - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); - } + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; + state.unbindTexture(); - if ( dstTexture.isData3DTexture ) { + }; - textures.setTexture3D( dstTexture, 0 ); - glTarget = 32879; + this.initTexture = function ( texture ) { - } else if ( dstTexture.isDataArrayTexture ) { + if ( texture.isCubeTexture ) { - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = 35866; + textures.setTextureCube( texture, 0 ); - } else { + } else if ( texture.isData3DTexture ) { - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; + textures.setTexture3D( texture, 0 ); - } + } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + textures.setTexture2DArray( texture, 0 ); - const unpackRowLen = _gl.getParameter( 3314 ); - const unpackImageHeight = _gl.getParameter( 32878 ); - const unpackSkipPixels = _gl.getParameter( 3316 ); - const unpackSkipRows = _gl.getParameter( 3315 ); - const unpackSkipImages = _gl.getParameter( 32877 ); + } else { - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; + textures.setTexture2D( texture, 0 ); - _gl.pixelStorei( 3314, image.width ); - _gl.pixelStorei( 32878, image.height ); - _gl.pixelStorei( 3316, sourceBox.min.x ); - _gl.pixelStorei( 3315, sourceBox.min.y ); - _gl.pixelStorei( 32877, sourceBox.min.z ); + } - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { + state.unbindTexture(); - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); + }; - } else { + this.resetState = function () { - if ( srcTexture.isCompressedArrayTexture ) { + _currentActiveCubeFace = 0; + _currentActiveMipmapLevel = 0; + _currentRenderTarget = null; - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); + state.reset(); + bindingStates.reset(); - } else { + }; - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - } + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); } - _gl.pixelStorei( 3314, unpackRowLen ); - _gl.pixelStorei( 32878, unpackImageHeight ); - _gl.pixelStorei( 3316, unpackSkipPixels ); - _gl.pixelStorei( 3315, unpackSkipRows ); - _gl.pixelStorei( 32877, unpackSkipImages ); + } - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); + get coordinateSystem() { - state.unbindTexture(); + return WebGLCoordinateSystem; - }; + } - this.initTexture = function ( texture ) { + get outputColorSpace() { - if ( texture.isCubeTexture ) { + return this._outputColorSpace; - textures.setTextureCube( texture, 0 ); + } - } else if ( texture.isData3DTexture ) { + set outputColorSpace( colorSpace ) { - textures.setTexture3D( texture, 0 ); + this._outputColorSpace = colorSpace; - } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + const gl = this.getContext(); + gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; + gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; - textures.setTexture2DArray( texture, 0 ); + } - } else { + get outputEncoding() { // @deprecated, r152 - textures.setTexture2D( texture, 0 ); + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; - } + } - state.unbindTexture(); + set outputEncoding( encoding ) { // @deprecated, r152 - }; + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; - this.resetState = function () { + } - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; + get useLegacyLights() { // @deprecated, r155 - state.reset(); - bindingStates.reset(); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + return this._useLegacyLights; - }; + } - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + set useLegacyLights( value ) { // @deprecated, r155 - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + this._useLegacyLights = value; } @@ -28722,29 +30488,13 @@ const data = super.toJSON( meta ); if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - if ( this.backgroundBlurriness > 0 ) data.backgroundBlurriness = this.backgroundBlurriness; - if ( this.backgroundIntensity !== 1 ) data.backgroundIntensity = this.backgroundIntensity; + if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; + if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; return data; } - // @deprecated - - get autoUpdate() { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - return this.matrixWorldAutoUpdate; - - } - - set autoUpdate( value ) { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - this.matrixWorldAutoUpdate = value; - - } - } class MeshPhongMaterial extends Material { @@ -29042,6 +30792,7 @@ * The azimuthal angle (theta) is measured from the positive z-axis. */ + class Spherical { constructor( radius = 1, phi = 0, theta = 0 ) { @@ -29140,7 +30891,7 @@ } - // This set of controls performs orbiting, dollying (zooming), and panning. + // OrbitControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). // // Orbit - left mouse / touch: one-finger move @@ -29150,6 +30901,9 @@ const _changeEvent = { type: 'change' }; const _startEvent = { type: 'start' }; const _endEvent = { type: 'end' }; + const _ray = new Ray(); + const _plane = new Plane(); + const TILT_LIMIT = Math.cos( 70 * MathUtils.DEG2RAD ); class OrbitControls extends EventDispatcher { @@ -29167,6 +30921,9 @@ // "target" sets the location of focus, where the object orbits around this.target = new Vector3(); + // Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect + this.cursor = new Vector3(); + // How far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; this.maxDistance = Infinity; @@ -29175,6 +30932,10 @@ this.minZoom = 0; this.maxZoom = Infinity; + // Limit camera target within a spherical area around the cursor + this.minTargetRadius = 0; + this.maxTargetRadius = Infinity; + // How far you can orbit vertically, upper and lower limits. // Range is 0 to Math.PI radians. this.minPolarAngle = 0; // radians @@ -29204,6 +30965,7 @@ this.panSpeed = 1.0; this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up this.keyPanSpeed = 7.0; // pixels moved per arrow key push + this.zoomToCursor = false; // Set to true to automatically rotate around the target // If auto-rotate is enabled, you must call controls.update() in your animation loop @@ -29256,6 +31018,13 @@ }; + this.stopListenToKeyEvents = function () { + + this._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + this._domElementKeyEvents = null; + + }; + this.saveState = function () { scope.target0.copy( scope.target ); @@ -29290,10 +31059,11 @@ const lastPosition = new Vector3(); const lastQuaternion = new Quaternion(); + const lastTargetPosition = new Vector3(); const twoPI = 2 * Math.PI; - return function update() { + return function update( deltaTime = null ) { const position = scope.object.position; @@ -29307,7 +31077,7 @@ if ( scope.autoRotate && state === STATE.NONE ) { - rotateLeft( getAutoRotationAngle() ); + rotateLeft( getAutoRotationAngle( deltaTime ) ); } @@ -29354,11 +31124,6 @@ spherical.makeSafe(); - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - // move target to panned location if ( scope.enableDamping === true ) { @@ -29371,6 +31136,23 @@ } + // Limit the target distance from the cursor to create a sphere around the center of interest + scope.target.sub( scope.cursor ); + scope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius ); + scope.target.add( scope.cursor ); + + // adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera + // we adjust zoom later in these cases + if ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) { + + spherical.radius = clampDistance( spherical.radius ); + + } else { + + spherical.radius = clampDistance( spherical.radius * scale ); + + } + offset.setFromSpherical( spherical ); // rotate offset back to "camera-up-vector-is-up" space @@ -29395,7 +31177,91 @@ } + // adjust camera position + let zoomChanged = false; + if ( scope.zoomToCursor && performCursorZoom ) { + + let newRadius = null; + if ( scope.object.isPerspectiveCamera ) { + + // move the camera down the pointer ray + // this method avoids floating point error + const prevRadius = offset.length(); + newRadius = clampDistance( prevRadius * scale ); + + const radiusDelta = prevRadius - newRadius; + scope.object.position.addScaledVector( dollyDirection, radiusDelta ); + scope.object.updateMatrixWorld(); + + } else if ( scope.object.isOrthographicCamera ) { + + // adjust the ortho camera position based on zoom changes + const mouseBefore = new Vector3( mouse.x, mouse.y, 0 ); + mouseBefore.unproject( scope.object ); + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + const mouseAfter = new Vector3( mouse.x, mouse.y, 0 ); + mouseAfter.unproject( scope.object ); + + scope.object.position.sub( mouseAfter ).add( mouseBefore ); + scope.object.updateMatrixWorld(); + + newRadius = offset.length(); + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' ); + scope.zoomToCursor = false; + + } + + // handle the placement of the target + if ( newRadius !== null ) { + + if ( this.screenSpacePanning ) { + + // position the orbit target in front of the new camera position + scope.target.set( 0, 0, - 1 ) + .transformDirection( scope.object.matrix ) + .multiplyScalar( newRadius ) + .add( scope.object.position ); + + } else { + + // get the ray and translation plane to compute target + _ray.origin.copy( scope.object.position ); + _ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix ); + + // if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid + // extremely large values + if ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) { + + object.lookAt( scope.target ); + + } else { + + _plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target ); + _ray.intersectPlane( _plane, scope.target ); + + } + + } + + } + + } else if ( scope.object.isOrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } + scale = 1; + performCursorZoom = false; // update condition is: // min(camera displacement, camera rotation in radians)^2 > EPS @@ -29403,13 +31269,14 @@ if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS || + lastTargetPosition.distanceToSquared( scope.target ) > 0 ) { scope.dispatchEvent( _changeEvent ); lastPosition.copy( scope.object.position ); lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; + lastTargetPosition.copy( scope.target ); return true; @@ -29426,7 +31293,7 @@ scope.domElement.removeEventListener( 'contextmenu', onContextMenu ); scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); - scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.removeEventListener( 'pointercancel', onPointerUp ); scope.domElement.removeEventListener( 'wheel', onMouseWheel ); scope.domElement.removeEventListener( 'pointermove', onPointerMove ); @@ -29436,6 +31303,7 @@ if ( scope._domElementKeyEvents !== null ) { scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + scope._domElementKeyEvents = null; } @@ -29470,7 +31338,6 @@ let scale = 1; const panOffset = new Vector3(); - let zoomChanged = false; const rotateStart = new Vector2(); const rotateEnd = new Vector2(); @@ -29484,18 +31351,31 @@ const dollyEnd = new Vector2(); const dollyDelta = new Vector2(); + const dollyDirection = new Vector3(); + const mouse = new Vector2(); + let performCursorZoom = false; + const pointers = []; const pointerPositions = {}; - function getAutoRotationAngle() { + function getAutoRotationAngle( deltaTime ) { + + if ( deltaTime !== null ) { + + return ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime; + + } else { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + } } - function getZoomScale() { + function getZoomScale( delta ) { - return Math.pow( 0.95, scope.zoomSpeed ); + const normalized_delta = Math.abs( delta ) / ( 100 * ( window.devicePixelRatio | 0 ) ); + return Math.pow( 0.95, scope.zoomSpeed * normalized_delta ); } @@ -29594,16 +31474,10 @@ function dollyOut( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale /= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -29615,16 +31489,10 @@ function dollyIn( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale *= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -29634,6 +31502,35 @@ } + function updateZoomParameters( x, y ) { + + if ( ! scope.zoomToCursor ) { + + return; + + } + + performCursorZoom = true; + + const rect = scope.domElement.getBoundingClientRect(); + const dx = x - rect.left; + const dy = y - rect.top; + const w = rect.width; + const h = rect.height; + + mouse.x = ( dx / w ) * 2 - 1; + mouse.y = - ( dy / h ) * 2 + 1; + + dollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize(); + + } + + function clampDistance( dist ) { + + return Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) ); + + } + // // event callbacks - update the object state // @@ -29646,6 +31543,7 @@ function handleMouseDownDolly( event ) { + updateZoomParameters( event.clientX, event.clientX ); dollyStart.set( event.clientX, event.clientY ); } @@ -29682,11 +31580,11 @@ if ( dollyDelta.y > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( dollyDelta.y ) ); } else if ( dollyDelta.y < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( dollyDelta.y ) ); } @@ -29712,13 +31610,15 @@ function handleMouseWheel( event ) { + updateZoomParameters( event.clientX, event.clientY ); + if ( event.deltaY < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( event.deltaY ) ); } else if ( event.deltaY > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( event.deltaY ) ); } @@ -29806,16 +31706,18 @@ } - function handleTouchStartRotate() { + function handleTouchStartRotate( event ) { if ( pointers.length === 1 ) { - rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + rotateStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); rotateStart.set( x, y ); @@ -29823,16 +31725,18 @@ } - function handleTouchStartPan() { + function handleTouchStartPan( event ) { if ( pointers.length === 1 ) { - panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + panStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); panStart.set( x, y ); @@ -29840,10 +31744,12 @@ } - function handleTouchStartDolly() { + function handleTouchStartDolly( event ) { + + const position = getSecondPointerPosition( event ); - const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX; - const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY; + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; const distance = Math.sqrt( dx * dx + dy * dy ); @@ -29851,19 +31757,19 @@ } - function handleTouchStartDollyPan() { + function handleTouchStartDollyPan( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enablePan ) handleTouchStartPan(); + if ( scope.enablePan ) handleTouchStartPan( event ); } - function handleTouchStartDollyRotate() { + function handleTouchStartDollyRotate( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enableRotate ) handleTouchStartRotate(); + if ( scope.enableRotate ) handleTouchStartRotate( event ); } @@ -29938,6 +31844,11 @@ dollyStart.copy( dollyEnd ); + const centerX = ( event.pageX + position.x ) * 0.5; + const centerY = ( event.pageY + position.y ) * 0.5; + + updateZoomParameters( centerX, centerY ); + } function handleTouchMoveDollyPan( event ) { @@ -30007,26 +31918,20 @@ function onPointerUp( event ) { - removePointer( event ); - - if ( pointers.length === 0 ) { - - scope.domElement.releasePointerCapture( event.pointerId ); - - scope.domElement.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.removeEventListener( 'pointerup', onPointerUp ); + removePointer( event ); - } + if ( pointers.length === 0 ) { - scope.dispatchEvent( _endEvent ); + scope.domElement.releasePointerCapture( event.pointerId ); - state = STATE.NONE; + scope.domElement.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.removeEventListener( 'pointerup', onPointerUp ); - } + } - function onPointerCancel( event ) { + scope.dispatchEvent( _endEvent ); - removePointer( event ); + state = STATE.NONE; } @@ -30195,7 +32100,7 @@ if ( scope.enableRotate === false ) return; - handleTouchStartRotate(); + handleTouchStartRotate( event ); state = STATE.TOUCH_ROTATE; @@ -30205,7 +32110,7 @@ if ( scope.enablePan === false ) return; - handleTouchStartPan(); + handleTouchStartPan( event ); state = STATE.TOUCH_PAN; @@ -30227,7 +32132,7 @@ if ( scope.enableZoom === false && scope.enablePan === false ) return; - handleTouchStartDollyPan(); + handleTouchStartDollyPan( event ); state = STATE.TOUCH_DOLLY_PAN; @@ -30237,7 +32142,7 @@ if ( scope.enableZoom === false && scope.enableRotate === false ) return; - handleTouchStartDollyRotate(); + handleTouchStartDollyRotate( event ); state = STATE.TOUCH_DOLLY_ROTATE; @@ -30329,7 +32234,7 @@ function addPointer( event ) { - pointers.push( event ); + pointers.push( event.pointerId ); } @@ -30339,7 +32244,7 @@ for ( let i = 0; i < pointers.length; i ++ ) { - if ( pointers[ i ].pointerId == event.pointerId ) { + if ( pointers[ i ] == event.pointerId ) { pointers.splice( i, 1 ); return; @@ -30367,9 +32272,9 @@ function getSecondPointerPosition( event ) { - const pointer = ( event.pointerId === pointers[ 0 ].pointerId ) ? pointers[ 1 ] : pointers[ 0 ]; + const pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ]; - return pointerPositions[ pointer.pointerId ]; + return pointerPositions[ pointerId ]; } @@ -30378,7 +32283,7 @@ scope.domElement.addEventListener( 'contextmenu', onContextMenu ); scope.domElement.addEventListener( 'pointerdown', onPointerDown ); - scope.domElement.addEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.addEventListener( 'pointercancel', onPointerUp ); scope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } ); // force an update at start @@ -30389,10 +32294,8 @@ } - - // This set of controls performs orbiting, dollying (zooming), and panning. + // MapControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). - // This is very similar to OrbitControls, another set of touch behavior // // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish @@ -30406,11 +32309,9 @@ this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up - this.mouseButtons.LEFT = MOUSE.PAN; - this.mouseButtons.RIGHT = MOUSE.ROTATE; + this.mouseButtons = { LEFT: MOUSE.PAN, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.ROTATE }; - this.touches.ONE = TOUCH.PAN; - this.touches.TWO = TOUCH.DOLLY_ROTATE; + this.touches = { ONE: TOUCH.PAN, TWO: TOUCH.DOLLY_ROTATE }; } @@ -31719,7 +33620,7 @@ class MapView extends Mesh { constructor(root = MapView.PLANAR, provider = new OpenStreetMapsProvider(), heightProvider = null) { - super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0 })); + super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0, depthWrite: false, colorWrite: false })); this.lod = null; this.provider = null; this.heightProvider = null; diff --git a/examples/providers.js b/examples/providers.js index 4ca1c93..2fd9a6a 100644 --- a/examples/providers.js +++ b/examples/providers.js @@ -3,10 +3,11 @@ /** * @license - * Copyright 2010-2022 Three.js Authors + * Copyright 2010-2023 Three.js Authors * SPDX-License-Identifier: MIT */ - const REVISION = '147'; + const REVISION = '160'; + const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; const CullFaceNone = 0; @@ -40,6 +41,10 @@ const DstColorFactor = 208; const OneMinusDstColorFactor = 209; const SrcAlphaSaturateFactor = 210; + const ConstantColorFactor = 211; + const OneMinusConstantColorFactor = 212; + const ConstantAlphaFactor = 213; + const OneMinusConstantAlphaFactor = 214; const NeverDepth = 0; const AlwaysDepth = 1; const LessDepth = 2; @@ -57,6 +62,7 @@ const CineonToneMapping = 3; const ACESFilmicToneMapping = 4; const CustomToneMapping = 5; + const AgXToneMapping = 6; const UVMapping = 300; const CubeReflectionMapping = 301; @@ -85,7 +91,6 @@ const UnsignedShort5551Type = 1018; const UnsignedInt248Type = 1020; const AlphaFormat = 1021; - const RGBFormat = 1022; // @deprecated since r137 const RGBAFormat = 1023; const LuminanceFormat = 1024; const LuminanceAlphaFormat = 1025; @@ -123,22 +128,53 @@ const RGBA_ASTC_12x10_Format = 37820; const RGBA_ASTC_12x12_Format = 37821; const RGBA_BPTC_Format = 36492; + const RGB_BPTC_SIGNED_Format = 36494; + const RGB_BPTC_UNSIGNED_Format = 36495; + const RED_RGTC1_Format = 36283; + const SIGNED_RED_RGTC1_Format = 36284; + const RED_GREEN_RGTC2_Format = 36285; + const SIGNED_RED_GREEN_RGTC2_Format = 36286; + /** @deprecated Use LinearSRGBColorSpace or NoColorSpace in three.js r152+. */ const LinearEncoding = 3000; + /** @deprecated Use SRGBColorSpace in three.js r152+. */ const sRGBEncoding = 3001; const BasicDepthPacking = 3200; const RGBADepthPacking = 3201; const TangentSpaceNormalMap = 0; const ObjectSpaceNormalMap = 1; + + // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. + const NoColorSpace = ''; const SRGBColorSpace = 'srgb'; const LinearSRGBColorSpace = 'srgb-linear'; + const DisplayP3ColorSpace = 'display-p3'; + const LinearDisplayP3ColorSpace = 'display-p3-linear'; + + const LinearTransfer = 'linear'; + const SRGBTransfer = 'srgb'; + + const Rec709Primaries = 'rec709'; + const P3Primaries = 'p3'; const KeepStencilOp = 7680; const AlwaysStencilFunc = 519; + const NeverCompare = 512; + const LessCompare = 513; + const EqualCompare = 514; + const LessEqualCompare = 515; + const GreaterCompare = 516; + const NotEqualCompare = 517; + const GreaterEqualCompare = 518; + const AlwaysCompare = 519; + const StaticDrawUsage = 35044; const GLSL3 = '300 es'; const _SRGBAFormat = 1035; // fallback for WebGL 1 + const WebGLCoordinateSystem = 2000; + const WebGPUCoordinateSystem = 2001; + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -226,6 +262,8 @@ 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' ]; + let _seed = 1234567; + const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; @@ -261,6 +299,28 @@ } + // Linear mapping from range to range + function mapLinear( x, a1, a2, b1, b2 ) { + + 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 ) { @@ -268,18 +328,167 @@ } + // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ + function damp( x, y, lambda, dt ) { + + return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); + + } + + // https://www.desmos.com/calculator/vcsjnyz7x4 + function pingpong( x, length = 1 ) { + + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); + + } + + // http://en.wikipedia.org/wiki/Smoothstep + function smoothstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + + } + + function smootherstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + + } + + // Random integer from interval + function randInt( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + } + + // Random float from interval + function randFloat( low, high ) { + + return low + Math.random() * ( high - low ); + + } + + // Random float from <-range/2, range/2> interval + function randFloatSpread( range ) { + + return range * ( 0.5 - Math.random() ); + + } + + // Deterministic pseudo-random float in the interval [ 0, 1 ] + function seededRandom( s ) { + + if ( s !== undefined ) _seed = s; + + // Mulberry32 generator + + let t = _seed += 0x6D2B79F5; + + t = Math.imul( t ^ t >>> 15, t | 1 ); + + t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); + + return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; + + } + + function degToRad( degrees ) { + + return degrees * DEG2RAD; + + } + + function radToDeg( radians ) { + + return radians * RAD2DEG; + + } + function isPowerOfTwo( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } + function ceilPowerOfTwo( value ) { + + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + + } + function floorPowerOfTwo( value ) { return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); } + function setQuaternionFromProperEuler( q, a, b, c, order ) { + + // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles + + // rotations are applied to the axes in the order specified by 'order' + // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' + // angles are in radians + + const cos = Math.cos; + const sin = Math.sin; + + const c2 = cos( b / 2 ); + const s2 = sin( b / 2 ); + + const c13 = cos( ( a + c ) / 2 ); + const s13 = sin( ( a + c ) / 2 ); + + const c1_3 = cos( ( a - c ) / 2 ); + const s1_3 = sin( ( a - c ) / 2 ); + + const c3_1 = cos( ( c - a ) / 2 ); + const s3_1 = sin( ( c - a ) / 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 ); + + } + + } + function denormalize( value, array ) { switch ( array.constructor ) { @@ -288,6 +497,10 @@ return value; + case Uint32Array: + + return value / 4294967295.0; + case Uint16Array: return value / 65535.0; @@ -296,6 +509,10 @@ return value / 255.0; + case Int32Array: + + return Math.max( value / 2147483647.0, - 1.0 ); + case Int16Array: return Math.max( value / 32767.0, - 1.0 ); @@ -320,6 +537,10 @@ return value; + case Uint32Array: + + return Math.round( value * 4294967295.0 ); + case Uint16Array: return Math.round( value * 65535.0 ); @@ -328,6 +549,10 @@ return Math.round( value * 255.0 ); + case Int32Array: + + return Math.round( value * 2147483647.0 ); + case Int16Array: return Math.round( value * 32767.0 ); @@ -344,6 +569,33 @@ } + 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 ) { @@ -637,8 +889,8 @@ roundToZero() { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); return this; @@ -699,6 +951,20 @@ } + angleTo( v ) { + + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + + if ( denominator === 0 ) return Math.PI / 2; + + const theta = this.dot( v ) / denominator; + + // clamp, to handle numerical problems + + return Math.acos( clamp( theta, - 1, 1 ) ); + + } + distanceTo( v ) { return Math.sqrt( this.distanceToSquared( v ) ); @@ -809,7 +1075,7 @@ class Matrix3 { - constructor() { + constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { Matrix3.prototype.isMatrix3 = true; @@ -821,6 +1087,12 @@ ]; + if ( n11 !== undefined ) { + + this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); + + } + } set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { @@ -1070,13 +1342,27 @@ makeTranslation( x, y ) { - this.set( + if ( x.isVector2 ) { - 1, 0, x, - 0, 1, y, - 0, 0, 1 + 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; @@ -1194,3538 +1480,3548 @@ } - function SRGBToLinear( c ) { + function createCanvasElement() { - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + const canvas = createElementNS( 'canvas' ); + canvas.style.display = 'block'; + return canvas; } - function LinearToSRGB( c ) { + const _cache = {}; - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + function warnOnce( message ) { + + if ( message in _cache ) return; + + _cache[ message ] = true; + + console.warn( message ); } - // JavaScript RGB-to-RGB transforms, defined as - // FN[InputColorSpace][OutputColorSpace] callback functions. - const FN = { - [ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear }, - [ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB }, + /** + * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping + * or clipping. Based on W3C specifications for sRGB and Display P3, + * and ICC specifications for the D50 connection space. Values in/out + * are _linear_ sRGB and _linear_ Display P3. + * + * Note that both sRGB and Display P3 use the sRGB transfer functions. + * + * Reference: + * - http://www.russellcottrell.com/photo/matrixCalculator.htm + */ + + const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( + 0.8224621, 0.177538, 0.0, + 0.0331941, 0.9668058, 0.0, + 0.0170827, 0.0723974, 0.9105199, + ); + + const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( + 1.2249401, - 0.2249404, 0.0, + - 0.0420569, 1.0420571, 0.0, + - 0.0196376, - 0.0786361, 1.0982735 + ); + + /** + * Defines supported color spaces by transfer function and primaries, + * and provides conversions to/from the Linear-sRGB reference space. + */ + const COLOR_SPACES = { + [ LinearSRGBColorSpace ]: { + transfer: LinearTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color, + fromReference: ( color ) => color, + }, + [ SRGBColorSpace ]: { + transfer: SRGBTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color.convertSRGBToLinear(), + fromReference: ( color ) => color.convertLinearToSRGB(), + }, + [ LinearDisplayP3ColorSpace ]: { + transfer: LinearTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), + }, + [ DisplayP3ColorSpace ]: { + transfer: SRGBTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), + }, }; + const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); + const ColorManagement = { - legacyMode: true, + enabled: true, + + _workingColorSpace: LinearSRGBColorSpace, get workingColorSpace() { - return LinearSRGBColorSpace; + return this._workingColorSpace; }, set workingColorSpace( colorSpace ) { - console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' ); + if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { + + throw new Error( `Unsupported working color space, "${ colorSpace }".` ); + + } + + this._workingColorSpace = colorSpace; }, convert: function ( color, sourceColorSpace, targetColorSpace ) { - if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { + if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { return color; } - if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) { + const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; + const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; - const fn = FN[ sourceColorSpace ][ targetColorSpace ]; + return targetFromReference( sourceToReference( color ) ); - color.r = fn( color.r ); - color.g = fn( color.g ); - color.b = fn( color.b ); + }, - return color; + fromWorkingColorSpace: function ( color, targetColorSpace ) { - } + return this.convert( color, this._workingColorSpace, targetColorSpace ); + + }, - throw new Error( 'Unsupported color space conversion.' ); + toWorkingColorSpace: function ( color, sourceColorSpace ) { + + return this.convert( color, sourceColorSpace, this._workingColorSpace ); }, - fromWorkingColorSpace: function ( color, targetColorSpace ) { + getPrimaries: function ( colorSpace ) { - return this.convert( color, this.workingColorSpace, targetColorSpace ); + return COLOR_SPACES[ colorSpace ].primaries; }, - toWorkingColorSpace: function ( color, sourceColorSpace ) { + getTransfer: function ( colorSpace ) { - return this.convert( color, sourceColorSpace, this.workingColorSpace ); + if ( colorSpace === NoColorSpace ) return LinearTransfer; + + return COLOR_SPACES[ colorSpace ].transfer; }, }; - const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - - const _rgb$1 = { r: 0, g: 0, b: 0 }; - const _hslA = { h: 0, s: 0, l: 0 }; - const _hslB = { h: 0, s: 0, l: 0 }; - function hue2rgb( p, q, t ) { + function SRGBToLinear( c ) { - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); } - function toComponents( source, target ) { - - target.r = source.r; - target.g = source.g; - target.b = source.b; + function LinearToSRGB( c ) { - return target; + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; } - class Color { - - constructor( r, g, b ) { + let _canvas; - this.isColor = true; + class ImageUtils { - this.r = 1; - this.g = 1; - this.b = 1; + static getDataURL( image ) { - if ( g === undefined && b === undefined ) { + if ( /^data:/i.test( image.src ) ) { - // r is THREE.Color, hex or string - return this.set( r ); + return image.src; } - return this.setRGB( r, g, b ); + if ( typeof HTMLCanvasElement === 'undefined' ) { - } + return image.src; - set( value ) { + } - if ( value && value.isColor ) { + let canvas; - this.copy( value ); + if ( image instanceof HTMLCanvasElement ) { - } else if ( typeof value === 'number' ) { + canvas = image; - this.setHex( value ); + } else { - } else if ( typeof value === 'string' ) { + if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - this.setStyle( value ); + _canvas.width = image.width; + _canvas.height = image.height; - } + const context = _canvas.getContext( '2d' ); - return this; + if ( image instanceof ImageData ) { - } + context.putImageData( image, 0, 0 ); - setScalar( scalar ) { + } else { - this.r = scalar; - this.g = scalar; - this.b = scalar; + context.drawImage( image, 0, 0, image.width, image.height ); - return this; + } - } + canvas = _canvas; - setHex( hex, colorSpace = SRGBColorSpace ) { + } - hex = Math.floor( hex ); + if ( canvas.width > 2048 || canvas.height > 2048 ) { - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - ColorManagement.toWorkingColorSpace( this, colorSpace ); + return canvas.toDataURL( 'image/jpeg', 0.6 ); - return this; + } else { - } + return canvas.toDataURL( 'image/png' ); - setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { + } - this.r = r; - this.g = g; - this.b = b; + } - ColorManagement.toWorkingColorSpace( this, colorSpace ); + static sRGBToLinear( image ) { - return this; + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - } + const canvas = createElementNS( 'canvas' ); - setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { + canvas.width = image.width; + canvas.height = image.height; - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height ); - if ( s === 0 ) { + const imageData = context.getImageData( 0, 0, image.width, image.height ); + const data = imageData.data; - this.r = this.g = this.b = l; + for ( let i = 0; i < data.length; i ++ ) { - } else { + data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; + } - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); + context.putImageData( imageData, 0, 0 ); - } + return canvas; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + } else if ( image.data ) { - return this; + const data = image.data.slice( 0 ); - } + for ( let i = 0; i < data.length; i ++ ) { - setStyle( style, colorSpace = SRGBColorSpace ) { + if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - function handleAlpha( string ) { + data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - if ( string === undefined ) return; + } else { - if ( parseFloat( string ) < 1 ) { + // assuming float - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + data[ i ] = SRGBToLinear( data[ i ] ); + + } } - } + return { + data: data, + width: image.width, + height: image.height + }; + } else { - let m; + console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); + return image; - if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { + } - // rgb / hsl + } - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; + } - switch ( name ) { + let _sourceId = 0; - case 'rgb': - case 'rgba': + class Source { - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + constructor( data = null ) { - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + this.isSource = true; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + Object.defineProperty( this, 'id', { value: _sourceId ++ } ); - handleAlpha( color[ 4 ] ); + this.uuid = generateUUID(); - return this; + this.data = data; - } + this.version = 0; - 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) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + set needsUpdate( value ) { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + if ( value === true ) this.version ++; - handleAlpha( color[ 4 ] ); + } - return this; + toJSON( meta ) { - } + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - break; + if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - case 'hsl': - case 'hsla': + return meta.images[ this.uuid ]; - 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) - const h = parseFloat( color[ 1 ] ) / 360; - const s = parseFloat( color[ 2 ] ) / 100; - const l = parseFloat( color[ 3 ] ) / 100; + const output = { + uuid: this.uuid, + url: '' + }; - handleAlpha( color[ 4 ] ); + const data = this.data; - return this.setHSL( h, s, l, colorSpace ); + if ( data !== null ) { - } + let url; - break; + if ( Array.isArray( data ) ) { - } + // cube texture - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + url = []; - // hex color + for ( let i = 0, l = data.length; i < l; i ++ ) { - const hex = m[ 1 ]; - const size = hex.length; + if ( data[ i ].isDataTexture ) { - if ( size === 3 ) { + url.push( serializeImage( data[ i ].image ) ); - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + url.push( serializeImage( data[ i ] ) ); - return this; + } - } else if ( size === 6 ) { + } - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + // texture - return this; + url = serializeImage( data ); } + output.url = url; + } - if ( style && style.length > 0 ) { + if ( ! isRootObject ) { - return this.setColorName( style, colorSpace ); + meta.images[ this.uuid ] = output; } - return this; + return output; } - setColorName( style, colorSpace = SRGBColorSpace ) { + } - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; + function serializeImage( image ) { - if ( hex !== undefined ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - // red - this.setHex( hex, colorSpace ); + // default images - } else { + return ImageUtils.getDataURL( image ); - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + } else { - } + if ( image.data ) { - return this; + // images of DataTexture - } + return { + data: Array.from( image.data ), + width: image.width, + height: image.height, + type: image.data.constructor.name + }; - clone() { + } else { - return new this.constructor( this.r, this.g, this.b ); + console.warn( 'THREE.Texture: Unable to serialize Texture.' ); + return {}; + + } } - copy( color ) { + } - this.r = color.r; - this.g = color.g; - this.b = color.b; + let _textureId = 0; - return this; + class Texture extends EventDispatcher { - } + constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { - copySRGBToLinear( color ) { + super(); - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); + this.isTexture = true; - return this; + Object.defineProperty( this, 'id', { value: _textureId ++ } ); - } + this.uuid = generateUUID(); - copyLinearToSRGB( color ) { + this.name = ''; - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); + this.source = new Source( image ); + this.mipmaps = []; - return this; + this.mapping = mapping; + this.channel = 0; - } + this.wrapS = wrapS; + this.wrapT = wrapT; - convertSRGBToLinear() { + this.magFilter = magFilter; + this.minFilter = minFilter; - this.copySRGBToLinear( this ); + this.anisotropy = anisotropy; - return this; + this.format = format; + this.internalFormat = null; + this.type = type; - } + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; - convertLinearToSRGB() { + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); - this.copyLinearToSRGB( this ); + 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) - return this; + if ( typeof colorSpace === 'string' ) { - } + this.colorSpace = colorSpace; - getHex( colorSpace = SRGBColorSpace ) { + } else { // @deprecated, r152 - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - return clamp( _rgb$1.r * 255, 0, 255 ) << 16 ^ clamp( _rgb$1.g * 255, 0, 255 ) << 8 ^ clamp( _rgb$1.b * 255, 0, 255 ) << 0; + } + + + this.userData = {}; + + this.version = 0; + this.onUpdate = null; + + this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not + this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) } - getHexString( colorSpace = SRGBColorSpace ) { + get image() { - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); + return this.source.data; } - getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { + set image( value = null ) { - // h,s,l ranges are in 0.0 - 1.0 + this.source.data = value; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + } - const r = _rgb$1.r, g = _rgb$1.g, b = _rgb$1.b; + updateMatrix() { - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - let hue, saturation; - const lightness = ( min + max ) / 2.0; + } - if ( min === max ) { + clone() { - hue = 0; - saturation = 0; + return new this.constructor().copy( this ); - } else { + } - const delta = max - min; + copy( source ) { - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + this.name = source.name; - switch ( max ) { + this.source = source.source; + this.mipmaps = source.mipmaps.slice( 0 ); - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; + this.mapping = source.mapping; + this.channel = source.channel; - } + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; - hue /= 6; + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; - } + this.anisotropy = source.anisotropy; - target.h = hue; - target.s = saturation; - target.l = lightness; + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; - return target; + 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 ); - getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.colorSpace = source.colorSpace; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - target.r = _rgb$1.r; - target.g = _rgb$1.g; - target.b = _rgb$1.b; + this.needsUpdate = true; - return target; + return this; } - getStyle( colorSpace = SRGBColorSpace ) { + toJSON( meta ) { - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - if ( colorSpace !== SRGBColorSpace ) { + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ _rgb$1.r } ${ _rgb$1.g } ${ _rgb$1.b })`; + return meta.textures[ this.uuid ]; } - return `rgb(${( _rgb$1.r * 255 ) | 0},${( _rgb$1.g * 255 ) | 0},${( _rgb$1.b * 255 ) | 0})`; + const output = { - } + metadata: { + version: 4.6, + type: 'Texture', + generator: 'Texture.toJSON' + }, - offsetHSL( h, s, l ) { + uuid: this.uuid, + name: this.name, - this.getHSL( _hslA ); + image: this.source.toJSON( meta ).uuid, - _hslA.h += h; _hslA.s += s; _hslA.l += l; + mapping: this.mapping, + channel: this.channel, - this.setHSL( _hslA.h, _hslA.s, _hslA.l ); + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + center: [ this.center.x, this.center.y ], + rotation: this.rotation, - return this; + wrap: [ this.wrapS, this.wrapT ], - } + format: this.format, + internalFormat: this.internalFormat, + type: this.type, + colorSpace: this.colorSpace, - add( color ) { + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, - this.r += color.r; - this.g += color.g; - this.b += color.b; + flipY: this.flipY, - return this; + generateMipmaps: this.generateMipmaps, + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment - } + }; - addColors( color1, color2 ) { + if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + if ( ! isRootObject ) { - return this; + meta.textures[ this.uuid ] = output; - } + } - addScalar( s ) { + return output; - this.r += s; - this.g += s; - this.b += s; + } - return this; + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); } - sub( color ) { + transformUv( uv ) { - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); + if ( this.mapping !== UVMapping ) return uv; - return this; + uv.applyMatrix3( this.matrix ); - } + if ( uv.x < 0 || uv.x > 1 ) { - multiply( color ) { + switch ( this.wrapS ) { - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + case RepeatWrapping: - return this; + uv.x = uv.x - Math.floor( uv.x ); + break; - } + case ClampToEdgeWrapping: - multiplyScalar( s ) { + uv.x = uv.x < 0 ? 0 : 1; + break; - this.r *= s; - this.g *= s; - this.b *= s; + case MirroredRepeatWrapping: - return this; + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - } + uv.x = Math.ceil( uv.x ) - uv.x; - lerp( color, alpha ) { + } else { - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + uv.x = uv.x - Math.floor( uv.x ); - return this; + } - } + break; - lerpColors( color1, color2, alpha ) { + } - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; + } - return this; + if ( uv.y < 0 || uv.y > 1 ) { - } + switch ( this.wrapT ) { - lerpHSL( color, alpha ) { + case RepeatWrapping: - this.getHSL( _hslA ); - color.getHSL( _hslB ); + uv.y = uv.y - Math.floor( uv.y ); + break; - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); + case ClampToEdgeWrapping: - this.setHSL( h, s, l ); + uv.y = uv.y < 0 ? 0 : 1; + break; - return this; + case MirroredRepeatWrapping: - } + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - equals( c ) { + uv.y = Math.ceil( uv.y ) - uv.y; - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + } else { - } + uv.y = uv.y - Math.floor( uv.y ); - fromArray( array, offset = 0 ) { + } - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + break; - return this; + } - } + } - toArray( array = [], offset = 0 ) { + if ( this.flipY ) { - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; + uv.y = 1 - uv.y; - return array; + } + + return uv; } - fromBufferAttribute( attribute, index ) { + set needsUpdate( value ) { - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); + if ( value === true ) { - return this; + this.version ++; + this.source.needsUpdate = true; + + } } - toJSON() { + get encoding() { // @deprecated, r152 - return this.getHex(); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; } - *[ Symbol.iterator ]() { + set encoding( encoding ) { // @deprecated, r152 - yield this.r; - yield this.g; - yield this.b; + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; } } - Color.NAMES = _colorKeywords; + Texture.DEFAULT_IMAGE = null; + Texture.DEFAULT_MAPPING = UVMapping; + Texture.DEFAULT_ANISOTROPY = 1; - let _canvas; + class Vector4 { - class ImageUtils { + constructor( x = 0, y = 0, z = 0, w = 1 ) { - static getDataURL( image ) { + Vector4.prototype.isVector4 = true; - if ( /^data:/i.test( image.src ) ) { - - return image.src; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + } - if ( typeof HTMLCanvasElement == 'undefined' ) { + get width() { - return image.src; + return this.z; - } + } - let canvas; + set width( value ) { - if ( image instanceof HTMLCanvasElement ) { + this.z = value; - canvas = image; + } - } else { + get height() { - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); + return this.w; - _canvas.width = image.width; - _canvas.height = image.height; + } - const context = _canvas.getContext( '2d' ); + set height( value ) { - if ( image instanceof ImageData ) { + this.w = value; - context.putImageData( image, 0, 0 ); + } - } else { + set( x, y, z, w ) { - context.drawImage( image, 0, 0, image.width, image.height ); + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + return this; - canvas = _canvas; + } - } + setScalar( scalar ) { - if ( canvas.width > 2048 || canvas.height > 2048 ) { + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); + return this; - return canvas.toDataURL( 'image/jpeg', 0.6 ); + } - } else { + setX( x ) { - return canvas.toDataURL( 'image/png' ); + this.x = x; - } + return this; } - static sRGBToLinear( image ) { + setY( y ) { - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + this.y = y; - const canvas = createElementNS( 'canvas' ); + return this; - canvas.width = image.width; - canvas.height = image.height; + } - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); + setZ( z ) { - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; + this.z = z; - for ( let i = 0; i < data.length; i ++ ) { + return this; - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; + } - } + setW( w ) { - context.putImageData( imageData, 0, 0 ); + this.w = w; - return canvas; + return this; - } else if ( image.data ) { + } - const data = image.data.slice( 0 ); + setComponent( index, value ) { - for ( let i = 0; i < data.length; i ++ ) { + switch ( index ) { - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); + } - } else { + return this; - // assuming float + } - data[ i ] = SRGBToLinear( data[ i ] ); + getComponent( index ) { - } + switch ( index ) { - } + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); - return { - data: data, - width: image.width, - height: image.height - }; + } - } else { + } - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; + clone() { - } + return new this.constructor( this.x, this.y, this.z, this.w ); } - } + copy( v ) { - class Source { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - constructor( data = null ) { + return this; - this.isSource = true; + } - this.uuid = generateUUID(); + add( v ) { - this.data = data; + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - this.version = 0; + return this; } - set needsUpdate( value ) { - - if ( value === true ) this.version ++; + addScalar( s ) { - } + this.x += s; + this.y += s; + this.z += s; + this.w += s; - toJSON( meta ) { + return this; - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + } - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { + addVectors( a, b ) { - return meta.images[ this.uuid ]; + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - } + return this; - const output = { - uuid: this.uuid, - url: '' - }; + } - const data = this.data; + addScaledVector( v, s ) { - if ( data !== null ) { + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; - let url; + return this; - if ( Array.isArray( data ) ) { + } - // cube texture + sub( v ) { - url = []; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; - for ( let i = 0, l = data.length; i < l; i ++ ) { + return this; - if ( data[ i ].isDataTexture ) { + } - url.push( serializeImage( data[ i ].image ) ); + subScalar( s ) { - } else { + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - url.push( serializeImage( data[ i ] ) ); + return this; - } + } - } + subVectors( a, b ) { - } else { + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - // texture + return this; - url = serializeImage( data ); + } - } + multiply( v ) { - output.url = url; + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + this.w *= v.w; - } + return this; - if ( ! isRootObject ) { + } - meta.images[ this.uuid ] = output; + multiplyScalar( scalar ) { - } + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - return output; + return this; } - } + applyMatrix4( m ) { - function serializeImage( image ) { + const x = this.x, y = this.y, z = this.z, w = this.w; + const e = m.elements; - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + 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; - // default images + return this; - return ImageUtils.getDataURL( image ); + } - } else { - - if ( image.data ) { + divideScalar( scalar ) { - // images of DataTexture + return this.multiplyScalar( 1 / scalar ); - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; + } - } else { + setAxisAngleFromQuaternion( q ) { - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - } + // q is assumed to be normalized - } + this.w = 2 * Math.acos( q.w ); - } + const s = Math.sqrt( 1 - q.w * q.w ); - let textureId = 0; + if ( s < 0.0001 ) { - class Texture extends EventDispatcher { + this.x = 1; + this.y = 0; + this.z = 0; - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, encoding = LinearEncoding ) { + } else { - super(); + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - this.isTexture = true; + } - Object.defineProperty( this, 'id', { value: textureId ++ } ); + return this; - this.uuid = generateUUID(); + } - this.name = ''; + setAxisAngleFromRotationMatrix( m ) { - this.source = new Source( image ); - this.mipmaps = []; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - this.mapping = mapping; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - this.wrapS = wrapS; - this.wrapT = wrapT; + let angle, x, y, z; // variables for result + const epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - this.magFilter = magFilter; - this.minFilter = minFilter; + te = m.elements, - this.anisotropy = anisotropy; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - this.format = format; - this.internalFormat = null; - this.type = type; + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - 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 singularity is identity matrix so angle = 0 - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding; + this.set( 1, 0, 0, 0 ); - this.userData = {}; + return this; // zero angle, arbitrary axis - this.version = 0; - this.onUpdate = null; + } - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) + // otherwise this singularity is angle = 180 - } + angle = Math.PI; - get image() { + 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; - return this.source.data; + if ( ( xx > yy ) && ( xx > zz ) ) { - } + // m11 is the largest diagonal term - set image( value ) { + if ( xx < epsilon ) { - this.source.data = value; + x = 0; + y = 0.707106781; + z = 0.707106781; - } + } else { - updateMatrix() { + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + } - } + } else if ( yy > zz ) { - clone() { + // m22 is the largest diagonal term - return new this.constructor().copy( this ); + if ( yy < epsilon ) { - } + x = 0.707106781; + y = 0; + z = 0.707106781; - copy( source ) { + } else { - this.name = source.name; + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); + } - this.mapping = source.mapping; + } else { - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; + // m33 is the largest diagonal term so base result on this - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; + if ( zz < epsilon ) { - this.anisotropy = source.anisotropy; + x = 0.707106781; + y = 0.707106781; + z = 0; - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; + } else { - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - 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.encoding = source.encoding; + } - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + this.set( x, y, z, angle ); - this.needsUpdate = true; + return this; // return 180 deg rotation - return this; + } - } + // as we have reached here there are no singularities so we can handle normally - toJSON( meta ) { + let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + if ( Math.abs( s ) < 0.001 ) s = 1; - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case - return meta.textures[ this.uuid ]; + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - } + return this; - const output = { + } - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, + min( v ) { - uuid: this.uuid, - name: this.name, + 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 ); - image: this.source.toJSON( meta ).uuid, + return this; - mapping: this.mapping, + } - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, + max( v ) { - wrap: [ this.wrapS, this.wrapT ], + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); - format: this.format, - type: this.type, - encoding: this.encoding, + return this; - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, + } - flipY: this.flipY, + clamp( min, max ) { - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment + // assumes min < max, componentwise - }; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData; + return this; - if ( ! isRootObject ) { + } - meta.textures[ this.uuid ] = output; + clampScalar( minVal, maxVal ) { - } + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - return output; + return this; } - dispose() { + clampLength( min, max ) { - this.dispatchEvent( { type: 'dispose' } ); + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); } - transformUv( uv ) { + floor() { - if ( this.mapping !== UVMapping ) return uv; + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); - uv.applyMatrix3( this.matrix ); + return this; - if ( uv.x < 0 || uv.x > 1 ) { + } - switch ( this.wrapS ) { + ceil() { - case RepeatWrapping: + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); - uv.x = uv.x - Math.floor( uv.x ); - break; + return this; - case ClampToEdgeWrapping: + } - uv.x = uv.x < 0 ? 0 : 1; - break; + round() { - case MirroredRepeatWrapping: + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + return this; - uv.x = Math.ceil( uv.x ) - uv.x; + } - } else { + roundToZero() { - uv.x = uv.x - Math.floor( uv.x ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); + this.w = Math.trunc( this.w ); - } + return this; - break; + } - } + negate() { - } + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - if ( uv.y < 0 || uv.y > 1 ) { + return this; - switch ( this.wrapT ) { + } - case RepeatWrapping: + dot( v ) { - uv.y = uv.y - Math.floor( uv.y ); - break; + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - case ClampToEdgeWrapping: + } - uv.y = uv.y < 0 ? 0 : 1; - break; + lengthSq() { - case MirroredRepeatWrapping: + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + } - uv.y = Math.ceil( uv.y ) - uv.y; + length() { - } else { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - uv.y = uv.y - Math.floor( uv.y ); + } - } + manhattanLength() { - break; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - } + } - } + normalize() { - if ( this.flipY ) { + return this.divideScalar( this.length() || 1 ); - uv.y = 1 - uv.y; + } - } + setLength( length ) { - return uv; + return this.normalize().multiplyScalar( length ); } - set needsUpdate( value ) { - - if ( value === true ) { + lerp( v, alpha ) { - this.version ++; - this.source.needsUpdate = true; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - } + return this; } - } - - Texture.DEFAULT_IMAGE = null; - Texture.DEFAULT_MAPPING = UVMapping; - Texture.DEFAULT_ANISOTROPY = 1; - - class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { + lerpVectors( v1, v2, alpha ) { - Vector4.prototype.isVector4 = true; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + this.w = v1.w + ( v2.w - v1.w ) * alpha; - this.x = x; - this.y = y; - this.z = z; - this.w = w; + return this; } - get width() { + equals( v ) { - return this.z; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); } - set width( value ) { - - this.z = value; - - } + fromArray( array, offset = 0 ) { - get height() { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; - return this.w; + return this; } - set height( value ) { + toArray( array = [], offset = 0 ) { - this.w = value; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; } - set( x, y, z, w ) { + fromBufferAttribute( attribute, index ) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); return this; } - setScalar( scalar ) { + random() { - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); return this; } - setX( x ) { - - this.x = x; + *[ Symbol.iterator ]() { - return this; + yield this.x; + yield this.y; + yield this.z; + yield this.w; } - setY( y ) { + } - this.y = y; + /* + 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 { - return this; + constructor( width = 1, height = 1, options = {} ) { - } + super(); - setZ( z ) { + this.isRenderTarget = true; - this.z = z; + this.width = width; + this.height = height; + this.depth = 1; - return this; + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; - } + this.viewport = new Vector4( 0, 0, width, height ); - setW( w ) { + const image = { width: width, height: height, depth: 1 }; - this.w = w; + if ( options.encoding !== undefined ) { - return this; + // @deprecated, r152 + warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - } + } - setComponent( index, value ) { + options = Object.assign( { + generateMipmaps: false, + internalFormat: null, + minFilter: LinearFilter, + depthBuffer: true, + stencilBuffer: false, + depthTexture: null, + samples: 0 + }, options ); - switch ( index ) { + this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); + this.texture.isRenderTargetTexture = true; - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); + this.texture.flipY = false; + this.texture.generateMipmaps = options.generateMipmaps; + this.texture.internalFormat = options.internalFormat; - } + this.depthBuffer = options.depthBuffer; + this.stencilBuffer = options.stencilBuffer; - return this; + this.depthTexture = options.depthTexture; + + this.samples = options.samples; } - getComponent( index ) { + setSize( width, height, depth = 1 ) { - switch ( index ) { + if ( this.width !== width || this.height !== height || this.depth !== depth ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); + this.width = width; + this.height = height; + this.depth = depth; + + this.texture.image.width = width; + this.texture.image.height = height; + this.texture.image.depth = depth; + + this.dispose(); } + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + } clone() { - return new this.constructor( this.x, this.y, this.z, this.w ); + return new this.constructor().copy( this ); } - copy( v ) { + copy( source ) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + this.width = source.width; + this.height = source.height; + this.depth = source.depth; - return this; + this.scissor.copy( source.scissor ); + this.scissorTest = source.scissorTest; - } + this.viewport.copy( source.viewport ); - add( v ) { + this.texture = source.texture.clone(); + this.texture.isRenderTargetTexture = true; - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; + // ensure image object is not shared, see #20328 - return this; + const image = Object.assign( {}, source.texture.image ); + this.texture.source = new Source( image ); - } + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; - addScalar( s ) { + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - this.x += s; - this.y += s; - this.z += s; - this.w += s; + this.samples = source.samples; return this; } - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; + dispose() { - return this; + this.dispatchEvent( { type: 'dispose' } ); } - 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; + } - } + class WebGLRenderTarget extends RenderTarget { - sub( v ) { + constructor( width = 1, height = 1, options = {} ) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; + super( width, height, options ); - return this; + this.isWebGLRenderTarget = true; } - subScalar( s ) { + } - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + class DataArrayTexture extends Texture { - return this; + constructor( data = null, width = 1, height = 1, depth = 1 ) { - } + super( null ); - subVectors( a, b ) { + this.isDataArrayTexture = true; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + this.image = { data, width, height, depth }; - return this; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.wrapR = ClampToEdgeWrapping; - multiply( v ) { + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; + } - return this; + } - } + class Data3DTexture extends Texture { - multiplyScalar( scalar ) { + constructor( data = null, width = 1, height = 1, depth = 1 ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + // We're going to add .setXXX() methods for setting properties later. + // Users can still set in DataTexture3D directly. + // + // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // texture.anisotropy = 16; + // + // See #14839 - return this; + super( null ); - } + this.isData3DTexture = true; - applyMatrix4( m ) { + this.image = { data, width, height, depth }; - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - 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; + this.wrapR = ClampToEdgeWrapping; - return this; + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; } - divideScalar( scalar ) { + } - return this.multiplyScalar( 1 / scalar ); + class Quaternion { - } + constructor( x = 0, y = 0, z = 0, w = 1 ) { - setAxisAngleFromQuaternion( q ) { + this.isQuaternion = true; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + this._x = x; + this._y = y; + this._z = z; + this._w = w; - // q is assumed to be normalized + } - this.w = 2 * Math.acos( q.w ); + static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - const s = Math.sqrt( 1 - q.w * q.w ); + // fuzz-free, array-based Quaternion SLERP operation - if ( s < 0.0001 ) { + let x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; - this.x = 1; - this.y = 0; - this.z = 0; + const x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; - } else { + if ( t === 0 ) { - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + dst[ dstOffset + 0 ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + return; } - return this; + if ( t === 1 ) { - } + dst[ dstOffset + 0 ] = x1; + dst[ dstOffset + 1 ] = y1; + dst[ dstOffset + 2 ] = z1; + dst[ dstOffset + 3 ] = w1; + return; - setAxisAngleFromRotationMatrix( m ) { + } - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + let s = 1 - t; + const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { - te = m.elements, + const sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { + } - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + const tDir = t * dir; - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; - // this singularity is identity matrix so angle = 0 + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { - this.set( 1, 0, 0, 0 ); + const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - return this; // zero angle, arbitrary axis + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; } - // otherwise this singularity is angle = 180 + } - angle = Math.PI; + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; - 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 > yy ) && ( xx > zz ) ) { + static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - // m11 is the largest diagonal term + const x0 = src0[ srcOffset0 ]; + const y0 = src0[ srcOffset0 + 1 ]; + const z0 = src0[ srcOffset0 + 2 ]; + const w0 = src0[ srcOffset0 + 3 ]; - if ( xx < epsilon ) { + const x1 = src1[ srcOffset1 ]; + const y1 = src1[ srcOffset1 + 1 ]; + const z1 = src1[ srcOffset1 + 2 ]; + const w1 = src1[ srcOffset1 + 3 ]; - x = 0; - y = 0.707106781; - z = 0.707106781; + dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; + dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; + dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; + dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - } else { + return dst; - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; + } - } + get x() { - } else if ( yy > zz ) { + return this._x; - // m22 is the largest diagonal term + } - if ( yy < epsilon ) { + set x( value ) { - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + this._x = value; + this._onChangeCallback(); - } + } - } else { + get y() { - // m33 is the largest diagonal term so base result on this + return this._y; - if ( zz < epsilon ) { + } - x = 0.707106781; - y = 0.707106781; - z = 0; + set y( value ) { - } else { + this._y = value; + this._onChangeCallback(); - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + } - } + get z() { - } + return this._z; - this.set( x, y, z, angle ); + } - return this; // return 180 deg rotation + set z( value ) { - } + this._z = value; + this._onChangeCallback(); - // as we have reached here there are no singularities so we can handle normally + } - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + get w() { - if ( Math.abs( s ) < 0.001 ) s = 1; + return this._w; - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case + } - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + set w( value ) { - return this; + this._w = value; + this._onChangeCallback(); } - min( v ) { + set( x, y, z, w ) { - 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 ); + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._onChangeCallback(); return this; } - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); + clone() { - return this; + return new this.constructor( this._x, this._y, this._z, this._w ); } - clamp( min, max ) { + copy( quaternion ) { - // assumes min < max, componentwise + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + this._onChangeCallback(); return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; + setFromEuler( euler, update = true ) { - } + const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - clampLength( min, max ) { + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - const length = this.length(); + const cos = Math.cos; + const sin = Math.sin; - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + 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 ); - floor() { + switch ( order ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); + 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; - return this; + 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; - ceil() { + 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; - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); + 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; - return this; + 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 ); - round() { + } - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); + if ( update === true ) this._onChangeCallback(); return this; } - roundToZero() { + setFromAxisAngle( axis, angle ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - return this; + // assumes axis is normalized - } + const halfAngle = angle / 2, s = Math.sin( halfAngle ); - negate() { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; + this._onChangeCallback(); return this; } - dot( v ) { + setFromRotationMatrix( m ) { - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - } + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - lengthSq() { + const te = m.elements, - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - } + trace = m11 + m22 + m33; - length() { + if ( trace > 0 ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + const s = 0.5 / Math.sqrt( trace + 1.0 ); - } + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - manhattanLength() { + } else if ( m11 > m22 && m11 > m33 ) { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - } + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - normalize() { + } else if ( m22 > m33 ) { - return this.divideScalar( this.length() || 1 ); + const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - } + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - setLength( length ) { + } else { - return this.normalize().multiplyScalar( length ); + const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - } + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - lerp( v, alpha ) { + } - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; + this._onChangeCallback(); return this; } - lerpVectors( v1, v2, alpha ) { + setFromUnitVectors( vFrom, vTo ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } + // assumes direction vectors vFrom and vTo are normalized - equals( v ) { + let r = vFrom.dot( vTo ) + 1; - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + if ( r < Number.EPSILON ) { - } + // vFrom and vTo point in opposite directions - fromArray( array, offset = 0 ) { + r = 0; - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - return this; + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; - } + } else { - toArray( array = [], offset = 0 ) { + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; + } - return array; + } else { - } + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - fromBufferAttribute( attribute, index ) { + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); + } - return this; + return this.normalize(); } - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); + angleTo( q ) { - return this; + return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); } - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - yield this.w; + rotateTowards( q, step ) { - } + const angle = this.angleTo( q ); - } + if ( angle === 0 ) return this; - /* - 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 WebGLRenderTarget extends EventDispatcher { + const t = Math.min( 1, step / angle ); - constructor( width = 1, height = 1, options = {} ) { + this.slerp( q, t ); - super(); + return this; - this.isWebGLRenderTarget = true; + } - this.width = width; - this.height = height; - this.depth = 1; + identity() { - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; + return this.set( 0, 0, 0, 1 ); - this.viewport = new Vector4( 0, 0, width, height ); + } - const image = { width: width, height: height, depth: 1 }; + invert() { - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; + // quaternion is assumed to have unit length - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + return this.conjugate(); - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; + } - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + conjugate() { - this.samples = options.samples !== undefined ? options.samples : 0; + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - } + this._onChangeCallback(); - setSize( width, height, depth = 1 ) { + return this; - if ( this.width !== width || this.height !== height || this.depth !== depth ) { + } - this.width = width; - this.height = height; - this.depth = depth; + dot( v ) { - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - this.dispose(); + } - } + lengthSq() { - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } - clone() { + length() { - return new this.constructor().copy( this ); + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); } - copy( source ) { + normalize() { - this.width = source.width; - this.height = source.height; - this.depth = source.depth; + let l = this.length(); - this.viewport.copy( source.viewport ); + if ( l === 0 ) { - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - // ensure image object is not shared, see #20328 + } else { - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); + l = 1 / l; - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + } - this.samples = source.samples; + this._onChangeCallback(); return this; } - dispose() { + multiply( q ) { - this.dispatchEvent( { type: 'dispose' } ); + return this.multiplyQuaternions( this, q ); } - } + premultiply( q ) { - class DataArrayTexture extends Texture { + return this.multiplyQuaternions( q, this ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + } - super( null ); + multiplyQuaternions( a, b ) { - this.isDataArrayTexture = true; + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - this.image = { data, width, height, depth }; + const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - this.wrapR = ClampToEdgeWrapping; + this._onChangeCallback(); - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + return this; } - } + slerp( qb, t ) { - class Data3DTexture extends Texture { + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + const x = this._x, y = this._y, z = this._z, w = this._w; - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - super( null ); + let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - this.isData3DTexture = true; + if ( cosHalfTheta < 0 ) { - this.image = { data, width, height, depth }; + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + cosHalfTheta = - cosHalfTheta; - this.wrapR = ClampToEdgeWrapping; + } else { - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + this.copy( qb ); - } + } - } + if ( cosHalfTheta >= 1.0 ) { - class Quaternion { + this._w = w; + this._x = x; + this._y = y; + this._z = z; - constructor( x = 0, y = 0, z = 0, w = 1 ) { + return this; - this.isQuaternion = true; + } - this._x = x; - this._y = y; - this._z = z; - this._w = w; + const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - } + if ( sqrSinHalfTheta <= Number.EPSILON ) { - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + 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; - // fuzz-free, array-based Quaternion SLERP operation + this.normalize(); // normalize calls _onChangeCallback() - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; + return this; } - if ( t === 1 ) { + const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - } + this._onChangeCallback(); - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + return this; - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; + } - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { + slerpQuaternions( qa, qb, t ) { - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); + return this.copy( qa ).slerp( qb, t ); - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; + } - } + random() { - const tDir = t * dir; + // Derived from http://planning.cs.uiuc.edu/node198.html + // Note, this source uses w, x, y, z ordering, + // so we swap the order below. - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; + const u1 = Math.random(); + const sqrt1u1 = Math.sqrt( 1 - u1 ); + const sqrtu1 = Math.sqrt( u1 ); - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { + const u2 = 2 * Math.PI * Math.random(); - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + const u3 = 2 * Math.PI * Math.random(); - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; + return this.set( + sqrt1u1 * Math.cos( u2 ), + sqrtu1 * Math.sin( u3 ), + sqrtu1 * Math.cos( u3 ), + sqrt1u1 * Math.sin( u2 ), + ); - } + } - } + equals( quaternion ) { - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); } - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; + fromArray( array, offset = 0 ) { - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; + this._onChangeCallback(); - return dst; + return this; } - get x() { + toArray( array = [], offset = 0 ) { - return this._x; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - } + return array; - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + fromBufferAttribute( attribute, index ) { - } + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); - get y() { + this._onChangeCallback(); - return this._y; + return this; } - set y( value ) { + toJSON() { - this._y = value; - this._onChangeCallback(); + return this.toArray(); } - get z() { + _onChange( callback ) { - return this._z; + this._onChangeCallback = callback; + + return this; } - set z( value ) { + _onChangeCallback() {} - this._z = value; - this._onChangeCallback(); + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._w; } - get w() { + } - return this._w; + class Vector3 { - } + constructor( x = 0, y = 0, z = 0 ) { - set w( value ) { + Vector3.prototype.isVector3 = true; - this._w = value; - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; } - set( x, y, z, w ) { + set( x, y, z ) { - this._x = x; - this._y = y; - this._z = z; - this._w = w; + if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; return this; } - clone() { + setScalar( scalar ) { - return new this.constructor( this._x, this._y, this._z, this._w ); + this.x = scalar; + this.y = scalar; + this.z = scalar; - } + return this; - copy( quaternion ) { + } - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + setX( x ) { - this._onChangeCallback(); + this.x = x; return this; } - setFromEuler( euler, update ) { - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; + setY( y ) { - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); + this.y = y; - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); + return this; - 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; + setZ( z ) { - 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; + this.z = z; - 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; + return this; - 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; + setComponent( index, value ) { - 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; + switch ( index ) { - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - if ( update !== false ) this._onChangeCallback(); - return this; } - setFromAxisAngle( axis, angle ) { + getComponent( index ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + switch ( index ) { - // assumes axis is normalized + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); - const halfAngle = angle / 2, s = Math.sin( halfAngle ); + } - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + } - this._onChangeCallback(); + clone() { - return this; + return new this.constructor( this.x, this.y, this.z ); } - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + copy( v ) { - const te = m.elements, + this.x = v.x; + this.y = v.y; + this.z = v.z; - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + return this; - trace = m11 + m22 + m33; + } - if ( trace > 0 ) { + add( v ) { - const s = 0.5 / Math.sqrt( trace + 1.0 ); + this.x += v.x; + this.y += v.y; + this.z += v.z; - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + return this; - } else if ( m11 > m22 && m11 > m33 ) { + } - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + addScalar( s ) { - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + this.x += s; + this.y += s; + this.z += s; - } else if ( m22 > m33 ) { + return this; - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + } - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + addVectors( a, b ) { - } else { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + return this; - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + } - } + addScaledVector( v, s ) { - this._onChangeCallback(); + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; return this; } - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized + sub( v ) { - let r = vFrom.dot( vTo ) + 1; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - if ( r < Number.EPSILON ) { + return this; - // vFrom and vTo point in opposite directions + } - r = 0; + subScalar( s ) { - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + this.x -= s; + this.y -= s; + this.z -= s; - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; + return this; - } else { + } - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; + subVectors( a, b ) { - } + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - } else { + return this; - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + } - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; + multiply( v ) { - } + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; - return this.normalize(); + return this; } - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } + multiplyScalar( scalar ) { - rotateTowards( q, step ) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - const angle = this.angleTo( q ); + return this; - if ( angle === 0 ) return this; + } - const t = Math.min( 1, step / angle ); + multiplyVectors( a, b ) { - this.slerp( q, t ); + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; return this; } - identity() { + applyEuler( euler ) { - return this.set( 0, 0, 0, 1 ); + return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); } - invert() { - - // quaternion is assumed to have unit length + applyAxisAngle( axis, angle ) { - return this.conjugate(); + return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); } - conjugate() { + applyMatrix3( m ) { - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - this._onChangeCallback(); + 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; } - dot( v ) { + applyNormalMatrix( m ) { - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + return this.applyMatrix3( m ).normalize(); } - lengthSq() { + applyMatrix4( m ) { - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - } + const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - length() { + 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 Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + return this; } - normalize() { - - let l = this.length(); + applyQuaternion( q ) { - if ( l === 0 ) { + // quaternion q is assumed to have unit length - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + const vx = this.x, vy = this.y, vz = this.z; + const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - } else { + // 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 ); - l = 1 / l; + // v + q.w * t + cross( q.xyz, t ); + this.x = vx + qw * tx + qy * tz - qz * ty; + this.y = vy + qw * ty + qz * tx - qx * tz; + this.z = vz + qw * tz + qx * ty - qy * tx; - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + return this; - } + } - this._onChangeCallback(); + project( camera ) { - return this; + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); } - multiply( q ) { + unproject( camera ) { - return this.multiplyQuaternions( this, q ); + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); } - premultiply( q ) { + transformDirection( m ) { - return this.multiplyQuaternions( q, this ); + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - } + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - multiplyQuaternions( a, b ) { + 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; - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + return this.normalize(); - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + } - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + divide( v ) { - this._onChangeCallback(); + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; return this; } - slerp( qb, t ) { + divideScalar( scalar ) { - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); + return this.multiplyScalar( 1 / scalar ); - const x = this._x, y = this._y, z = this._z, w = this._w; + } - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + min( v ) { - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { + return this; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + } - return this; + max( v ) { - } + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + return this; - if ( sqrSinHalfTheta <= Number.EPSILON ) { + } - 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; + clamp( min, max ) { - this.normalize(); - this._onChangeCallback(); + // assumes min < max, componentwise - return this; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - } + return this; - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + } - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); + clampScalar( minVal, maxVal ) { - this._onChangeCallback(); + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); return this; } - slerpQuaternions( qa, qb, t ) { - - return this.copy( qa ).slerp( qb, t ); - - } + clampLength( min, max ) { - random() { + const length = this.length(); - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); + } - const u2 = 2 * Math.PI * Math.random(); + floor() { - const u3 = 2 * Math.PI * Math.random(); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); + return this; } - equals( quaternion ) { + ceil() { - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - } + return this; - fromArray( array, offset = 0 ) { + } - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; + round() { - this._onChangeCallback(); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); return this; } - toArray( array = [], offset = 0 ) { + roundToZero() { - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); - return array; + return this; } - fromBufferAttribute( attribute, index ) { + negate() { - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; return this; } - _onChange( callback ) { - - this._onChangeCallback = callback; + dot( v ) { - return this; + return this.x * v.x + this.y * v.y + this.z * v.z; } - _onChangeCallback() {} + // TODO lengthSquared? - *[ Symbol.iterator ]() { + lengthSq() { - yield this._x; - yield this._y; - yield this._z; - yield this._w; + return this.x * this.x + this.y * this.y + this.z * this.z; } - } + length() { - class Vector3 { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - constructor( x = 0, y = 0, z = 0 ) { + } - Vector3.prototype.isVector3 = true; + manhattanLength() { - this.x = x; - this.y = y; - this.z = z; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); } - set( x, y, z ) { + normalize() { - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) + return this.divideScalar( this.length() || 1 ); - this.x = x; - this.y = y; - this.z = z; + } - return this; + setLength( length ) { + + return this.normalize().multiplyScalar( length ); } - setScalar( scalar ) { + lerp( v, alpha ) { - this.x = scalar; - this.y = scalar; - this.z = scalar; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; return this; } - setX( x ) { + lerpVectors( v1, v2, alpha ) { - this.x = x; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; return this; } - setY( y ) { - - this.y = y; + cross( v ) { - return this; + return this.crossVectors( this, v ); } - setZ( z ) { + crossVectors( a, b ) { - this.z = z; + 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; } - setComponent( index, value ) { + projectOnVector( v ) { - switch ( index ) { + const denominator = v.lengthSq(); - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); + if ( denominator === 0 ) return this.set( 0, 0, 0 ); - } + const scalar = v.dot( this ) / denominator; - return this; + return this.copy( v ).multiplyScalar( scalar ); } - getComponent( index ) { - - switch ( index ) { + projectOnPlane( planeNormal ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); + _vector$c.copy( this ).projectOnVector( planeNormal ); - } + return this.sub( _vector$c ); } - clone() { + reflect( normal ) { - return new this.constructor( this.x, this.y, this.z ); + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - } + return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - copy( v ) { + } - this.x = v.x; - this.y = v.y; - this.z = v.z; + angleTo( v ) { - return this; + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - } + if ( denominator === 0 ) return Math.PI / 2; - add( v ) { + const theta = this.dot( v ) / denominator; - this.x += v.x; - this.y += v.y; - this.z += v.z; + // clamp, to handle numerical problems - return this; + return Math.acos( clamp( theta, - 1, 1 ) ); } - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; + distanceTo( v ) { - return this; + return Math.sqrt( this.distanceToSquared( v ) ); } - addVectors( a, b ) { + distanceToSquared( v ) { - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return this; + return dx * dx + dy * dy + dz * dz; } - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; + manhattanDistanceTo( v ) { - return this; + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); } - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + setFromSpherical( s ) { - return this; + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); } - subScalar( s ) { + setFromSphericalCoords( radius, phi, theta ) { - this.x -= s; - this.y -= s; - this.z -= s; + const sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); return this; } - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + setFromCylindrical( c ) { - return this; + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); } - multiply( v ) { + setFromCylindricalCoords( radius, theta, y ) { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); return this; } - multiplyScalar( scalar ) { + setFromMatrixPosition( m ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; return this; } - multiplyVectors( a, b ) { + setFromMatrixScale( m ) { - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + const sx = this.setFromMatrixColumn( m, 0 ).length(); + const sy = this.setFromMatrixColumn( m, 1 ).length(); + const sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; return this; } - applyEuler( euler ) { + setFromMatrixColumn( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); + return this.fromArray( m.elements, index * 4 ); } - applyAxisAngle( axis, angle ) { + setFromMatrix3Column( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); + return this.fromArray( m.elements, index * 3 ); } - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + setFromEuler( e ) { - 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; + this.x = e._x; + this.y = e._y; + this.z = e._z; return this; } - applyNormalMatrix( m ) { + setFromColor( c ) { - return this.applyMatrix3( m ).normalize(); + this.x = c.r; + this.y = c.g; + this.z = c.b; + + return this; } - applyMatrix4( m ) { + equals( v ) { - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - 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; + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; return this; } - applyQuaternion( q ) { + toArray( array = [], offset = 0 ) { - const x = this.x, y = this.y, z = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - // calculate quat * vector + return array; - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = - qx * x - qy * y - qz * z; + } - // calculate result * inverse quat + fromBufferAttribute( attribute, index ) { - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); return this; } - project( camera ) { + random() { - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + + return this; } - unproject( camera ) { + randomDirection() { - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); + // Derived from https://mathworld.wolfram.com/SpherePointPicking.html - } + const u = ( Math.random() - 0.5 ) * 2; + const t = Math.random() * Math.PI * 2; + const f = Math.sqrt( 1 - u ** 2 ); - transformDirection( m ) { + this.x = f * Math.cos( t ); + this.y = f * Math.sin( t ); + this.z = u; - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + return this; - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + } - 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; + *[ Symbol.iterator ]() { - return this.normalize(); + yield this.x; + yield this.y; + yield this.z; } - divide( v ) { + } - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + const _vector$c = /*@__PURE__*/ new Vector3(); + const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - return this; + class Box3 { - } + constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - divideScalar( scalar ) { + this.isBox3 = true; - return this.multiplyScalar( 1 / scalar ); + this.min = min; + this.max = max; } - min( v ) { + set( min, max ) { - 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.min.copy( min ); + this.max.copy( max ); return this; } - max( v ) { + setFromArray( array ) { - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); + this.makeEmpty(); + + for ( let i = 0, il = array.length; i < il; i += 3 ) { + + this.expandByPoint( _vector$b.fromArray( array, i ) ); + + } return this; } - clamp( min, max ) { + setFromBufferAttribute( attribute ) { - // assumes min < max, componentwise + this.makeEmpty(); - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + for ( let i = 0, il = attribute.count; i < il; i ++ ) { + + this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); + + } return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + setFromPoints( points ) { - return this; + this.makeEmpty(); - } + for ( let i = 0, il = points.length; i < il; i ++ ) { - clampLength( min, max ) { + this.expandByPoint( points[ i ] ); - const length = this.length(); + } - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + return this; } - floor() { + setFromCenterAndSize( center, size ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); + const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); return this; } - ceil() { + setFromObject( object, precise = false ) { - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); + this.makeEmpty(); - return this; + return this.expandByObject( object, precise ); } - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); + clone() { - return this; + return new this.constructor().copy( this ); } - roundToZero() { + copy( box ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.min.copy( box.min ); + this.max.copy( box.max ); return this; } - negate() { + makeEmpty() { - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; return this; } - dot( v ) { + isEmpty() { - return this.x * v.x + this.y * v.y + this.z * v.z; + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - } + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - // TODO lengthSquared? + } - lengthSq() { + getCenter( target ) { - return this.x * this.x + this.y * this.y + this.z * this.z; + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); } - length() { + getSize( target ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); } - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } + expandByPoint( point ) { - normalize() { + this.min.min( point ); + this.max.max( point ); - return this.divideScalar( this.length() || 1 ); + return this; } - setLength( length ) { + expandByVector( vector ) { - return this.normalize().multiplyScalar( length ); + this.min.sub( vector ); + this.max.add( vector ); + + return this; } - lerp( v, alpha ) { + expandByScalar( scalar ) { - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); return this; } - lerpVectors( v1, v2, alpha ) { + expandByObject( object, precise = false ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - return this; + object.updateWorldMatrix( false, false ); - } + const geometry = object.geometry; - cross( v ) { + if ( geometry !== undefined ) { - return this.crossVectors( this, v ); + const positionAttribute = geometry.getAttribute( 'position' ); - } + // precise AABB computation based on vertex data requires at least a position attribute. + // instancing isn't supported so far and uses the normal (conservative) code path. - crossVectors( a, b ) { + if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; + for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + if ( object.isMesh === true ) { - return this; + object.getVertexPosition( i, _vector$b ); - } + } else { - projectOnVector( v ) { + _vector$b.fromBufferAttribute( positionAttribute, i ); - const denominator = v.lengthSq(); + } - if ( denominator === 0 ) return this.set( 0, 0, 0 ); + _vector$b.applyMatrix4( object.matrixWorld ); + this.expandByPoint( _vector$b ); - const scalar = v.dot( this ) / denominator; + } - return this.copy( v ).multiplyScalar( scalar ); + } else { - } + if ( object.boundingBox !== undefined ) { - projectOnPlane( planeNormal ) { + // object-level bounding box - _vector$c.copy( this ).projectOnVector( planeNormal ); + if ( object.boundingBox === null ) { - return this.sub( _vector$c ); + object.computeBoundingBox(); - } + } - reflect( normal ) { + _box$4.copy( object.boundingBox ); - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + } else { - } + // geometry-level bounding box - angleTo( v ) { + if ( geometry.boundingBox === null ) { - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + geometry.computeBoundingBox(); - if ( denominator === 0 ) return Math.PI / 2; + } - const theta = this.dot( v ) / denominator; + _box$4.copy( geometry.boundingBox ); - // clamp, to handle numerical problems + } - return Math.acos( clamp( theta, - 1, 1 ) ); + _box$4.applyMatrix4( object.matrixWorld ); - } + this.union( _box$4 ); - distanceTo( v ) { + } - return Math.sqrt( this.distanceToSquared( v ) ); + } - } + const children = object.children; - distanceToSquared( v ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + this.expandByObject( children[ i ], precise ); - return dx * dx + dy * dy + dz * dz; + } + + return this; } - manhattanDistanceTo( v ) { + containsPoint( point ) { - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ? false : true; } - setFromSpherical( s ) { + containsBox( box ) { - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; } - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; + getParameter( point, target ) { - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - return this; + 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 ) + ); } - setFromCylindrical( c ) { + intersectsBox( box ) { - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; } - setFromCylindricalCoords( radius, theta, y ) { + intersectsSphere( sphere ) { - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$b ); - return this; + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); } - setFromMatrixPosition( m ) { + intersectsPlane( plane ) { - const e = m.elements; + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; + let min, max; - return this; + if ( plane.normal.x > 0 ) { - } + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; - setFromMatrixScale( m ) { + } else { - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - this.x = sx; - this.y = sy; - this.z = sz; + } - return this; + if ( plane.normal.y > 0 ) { - } + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - setFromMatrixColumn( m, index ) { + } else { - return this.fromArray( m.elements, index * 4 ); + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; - } + } - setFromMatrix3Column( m, index ) { + if ( plane.normal.z > 0 ) { - return this.fromArray( m.elements, index * 3 ); + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; - } + } else { - setFromEuler( e ) { + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; - this.x = e._x; - this.y = e._y; - this.z = e._z; + } - return this; + return ( min <= - plane.constant && max >= - plane.constant ); } - equals( v ) { + intersectsTriangle( triangle ) { - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + if ( this.isEmpty() ) { - } + return false; - fromArray( array, offset = 0 ) { + } - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); - return this; + // translate triangle to aabb origin + _v0$2.subVectors( triangle.a, _center ); + _v1$7.subVectors( triangle.b, _center ); + _v2$4.subVectors( triangle.c, _center ); - } + // compute edge vectors for triangle + _f0.subVectors( _v1$7, _v0$2 ); + _f1.subVectors( _v2$4, _v1$7 ); + _f2.subVectors( _v0$2, _v2$4 ); - toArray( array = [], offset = 0 ) { + // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb + // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation + // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) + let axes = [ + 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, + _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, + - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 + ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; + return false; - return array; + } - } + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - fromBufferAttribute( attribute, index ) { + return false; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); + } - return this; + // finally testing the face normal of the triangle + // use already existing triangle edge vectors here + _triangleNormal.crossVectors( _f0, _f1 ); + axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + + return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); } - random() { + clampPoint( point, target ) { - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); + return target.copy( point ).clamp( this.min, this.max ); - return this; + } + + distanceToPoint( point ) { + + return this.clampPoint( point, _vector$b ).distanceTo( point ); } - randomDirection() { + getBoundingSphere( target ) { - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html + if ( this.isEmpty() ) { - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); + target.makeEmpty(); - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; + } else { - return this; + this.getCenter( target.center ); - } + target.radius = this.getSize( _vector$b ).length() * 0.5; - *[ Symbol.iterator ]() { + } - yield this.x; - yield this.y; - yield this.z; + return target; } - } + intersect( box ) { - const _vector$c = /*@__PURE__*/ new Vector3(); - const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + this.min.max( box.min ); + this.max.min( box.max ); - class Box3 { + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + return this; - this.isBox3 = true; + } - this.min = min; - this.max = max; + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; } - set( min, max ) { + applyMatrix4( matrix ) { - this.min.copy( min ); - this.max.copy( max ); + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.setFromPoints( _points ); return this; } - setFromArray( array ) { + translate( offset ) { - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + this.min.add( offset ); + this.max.add( offset ); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + return this; - for ( let i = 0, l = array.length; i < l; i += 3 ) { + } - const x = array[ i ]; - const y = array[ i + 1 ]; - const z = array[ i + 2 ]; + equals( box ) { - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + return box.min.equals( this.min ) && box.max.equals( this.max ); - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + } - } + } - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + 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() + ]; - return this; + const _vector$b = /*@__PURE__*/ new Vector3(); - } + const _box$4 = /*@__PURE__*/ new Box3(); - setFromBufferAttribute( attribute ) { + // triangle centered vertices - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + const _v0$2 = /*@__PURE__*/ new Vector3(); + const _v1$7 = /*@__PURE__*/ new Vector3(); + const _v2$4 = /*@__PURE__*/ new Vector3(); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + // triangle edge vectors - for ( let i = 0, l = attribute.count; i < l; i ++ ) { + const _f0 = /*@__PURE__*/ new Vector3(); + const _f1 = /*@__PURE__*/ new Vector3(); + const _f2 = /*@__PURE__*/ new Vector3(); - const x = attribute.getX( i ); - const y = attribute.getY( i ); - const z = attribute.getZ( i ); + const _center = /*@__PURE__*/ new Vector3(); + const _extents = /*@__PURE__*/ new Vector3(); + const _triangleNormal = /*@__PURE__*/ new Vector3(); + const _testAxis = /*@__PURE__*/ new Vector3(); - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + function satForAxes( axes, v0, v1, v2, extents ) { - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - } + _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 ) { - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is separating and we can exit + return false; - return this; + } } - setFromPoints( points ) { + return true; - this.makeEmpty(); + } - for ( let i = 0, il = points.length; i < il; i ++ ) { + const _box$3 = /*@__PURE__*/ new Box3(); + const _v1$6 = /*@__PURE__*/ new Vector3(); + const _v2$3 = /*@__PURE__*/ new Vector3(); - this.expandByPoint( points[ i ] ); + class Sphere { - } + constructor( center = new Vector3(), radius = - 1 ) { - return this; + this.isSphere = true; - } + this.center = center; + this.radius = radius; - setFromCenterAndSize( center, size ) { + } - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + set( center, radius ) { - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + this.center.copy( center ); + this.radius = radius; return this; } - setFromObject( object, precise = false ) { + setFromPoints( points, optionalCenter ) { - this.makeEmpty(); + const center = this.center; - return this.expandByObject( object, precise ); + if ( optionalCenter !== undefined ) { - } + center.copy( optionalCenter ); - clone() { + } else { - return new this.constructor().copy( this ); + _box$3.setFromPoints( points ).getCenter( center ); - } + } - copy( box ) { + let maxRadiusSq = 0; - this.min.copy( box.min ); - this.max.copy( box.max ); + for ( let i = 0, il = points.length; i < il; i ++ ) { + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); return this; } - makeEmpty() { + copy( sphere ) { - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + this.center.copy( sphere.center ); + this.radius = sphere.radius; return this; @@ -4733,1205 +5029,1271 @@ isEmpty() { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + return ( this.radius < 0 ); } - getCenter( target ) { + makeEmpty() { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; } - getSize( target ) { + containsPoint( point ) { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); } - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); + distanceToPoint( point ) { - return this; + return ( point.distanceTo( this.center ) - this.radius ); } - expandByVector( vector ) { + intersectsSphere( sphere ) { - this.min.sub( vector ); - this.max.add( vector ); + const radiusSum = this.radius + sphere.radius; - return this; + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); } - expandByScalar( scalar ) { + intersectsBox( box ) { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + return box.intersectsSphere( this ); - return this; + } + + intersectsPlane( plane ) { + + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; } - expandByObject( object, precise = false ) { + clampPoint( point, target ) { - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + const deltaLengthSq = this.center.distanceToSquared( point ); - object.updateWorldMatrix( false, false ); + target.copy( point ); - const geometry = object.geometry; + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - if ( geometry !== undefined ) { + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); - if ( precise && geometry.attributes != undefined && geometry.attributes.position !== undefined ) { + } - const position = geometry.attributes.position; - for ( let i = 0, l = position.count; i < l; i ++ ) { + return target; - _vector$b.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); + } - } + getBoundingBox( target ) { - } else { + if ( this.isEmpty() ) { - if ( geometry.boundingBox === null ) { + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; - geometry.computeBoundingBox(); + } - } + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); - _box$3.copy( geometry.boundingBox ); - _box$3.applyMatrix4( object.matrixWorld ); + return target; - this.union( _box$3 ); + } - } + applyMatrix4( matrix ) { - } + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - const children = object.children; + return this; - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - this.expandByObject( children[ i ], precise ); + translate( offset ) { - } + this.center.add( offset ); return this; } - containsPoint( point ) { + expandByPoint( point ) { - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; + if ( this.isEmpty() ) { - } + this.center.copy( point ); - containsBox( box ) { + this.radius = 0; - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; + return this; - } + } - getParameter( point, target ) { + _v1$6.subVectors( point, this.center ); - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + const lengthSq = _v1$6.lengthSq(); - 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 ) - ); + if ( lengthSq > ( this.radius * this.radius ) ) { - } + // calculate the minimal sphere - intersectsBox( box ) { + const length = Math.sqrt( lengthSq ); - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + const delta = ( length - this.radius ) * 0.5; - } + this.center.addScaledVector( _v1$6, delta / length ); - intersectsSphere( sphere ) { + this.radius += delta; - // 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 ); + return this; } - intersectsPlane( plane ) { + union( sphere ) { - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. + if ( sphere.isEmpty() ) { - let min, max; + return this; - if ( plane.normal.x > 0 ) { + } - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; + if ( this.isEmpty() ) { - } else { + this.copy( sphere ); - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + return this; } - if ( plane.normal.y > 0 ) { + if ( this.center.equals( sphere.center ) === true ) { - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; + this.radius = Math.max( this.radius, sphere.radius ); } else { - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); - } else { + this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); } - return ( min <= - plane.constant && max >= - plane.constant ); + return this; } - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } + equals( sphere ) { - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$4.subVectors( triangle.c, _center ); + } - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$4, _v1$7 ); - _f2.subVectors( _v0$2, _v2$4 ); + clone() { - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + return new this.constructor().copy( this ); - return false; + } - } + } - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + const _vector$a = /*@__PURE__*/ new Vector3(); + const _segCenter = /*@__PURE__*/ new Vector3(); + const _segDir = /*@__PURE__*/ new Vector3(); + const _diff = /*@__PURE__*/ new Vector3(); - return false; + const _edge1 = /*@__PURE__*/ new Vector3(); + const _edge2 = /*@__PURE__*/ new Vector3(); + const _normal$1 = /*@__PURE__*/ new Vector3(); - } + class Ray { - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); + this.origin = origin; + this.direction = direction; } - clampPoint( point, target ) { + set( origin, direction ) { - return target.copy( point ).clamp( this.min, this.max ); + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; } - distanceToPoint( point ) { + copy( ray ) { - const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); - return clampedPoint.sub( point ).length(); + return this; } - getBoundingSphere( target ) { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; + at( t, target ) { - return target; + return target.copy( this.origin ).addScaledVector( this.direction, t ); } - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); + lookAt( v ) { - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); + this.direction.copy( v ).sub( this.origin ).normalize(); return this; } - union( box ) { + recast( t ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.origin.copy( this.at( t, _vector$a ) ); return this; } - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + closestPointToPoint( point, target ) { - this.setFromPoints( _points ); + target.subVectors( point, this.origin ); - return this; + const directionDistance = target.dot( this.direction ); - } + if ( directionDistance < 0 ) { - translate( offset ) { + return target.copy( this.origin ); - this.min.add( offset ); - this.max.add( offset ); + } - return this; + return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); } - equals( box ) { + distanceToPoint( point ) { - return box.min.equals( this.min ) && box.max.equals( this.max ); + return Math.sqrt( this.distanceSqToPoint( point ) ); } - } + distanceSqToPoint( point ) { - 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() - ]; + const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - const _vector$b = /*@__PURE__*/ new Vector3(); + // point behind the ray - const _box$3 = /*@__PURE__*/ new Box3(); + if ( directionDistance < 0 ) { - // triangle centered vertices + return this.origin.distanceToSquared( point ); - const _v0$2 = /*@__PURE__*/ new Vector3(); - const _v1$7 = /*@__PURE__*/ new Vector3(); - const _v2$4 = /*@__PURE__*/ new Vector3(); + } - // triangle edge vectors + _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - const _f0 = /*@__PURE__*/ new Vector3(); - const _f1 = /*@__PURE__*/ new Vector3(); - const _f2 = /*@__PURE__*/ new Vector3(); + return _vector$a.distanceToSquared( point ); - const _center = /*@__PURE__*/ new Vector3(); - const _extents = /*@__PURE__*/ new Vector3(); - const _triangleNormal = /*@__PURE__*/ new Vector3(); - const _testAxis = /*@__PURE__*/ new Vector3(); + } - function satForAxes( axes, v0, v1, v2, extents ) { + distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { + // 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 - _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 ) { + _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + _segDir.copy( v1 ).sub( v0 ).normalize(); + _diff.copy( this.origin ).sub( _segCenter ); - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; - - } + const segExtent = v0.distanceTo( v1 ) * 0.5; + const a01 = - this.direction.dot( _segDir ); + const b0 = _diff.dot( this.direction ); + const b1 = - _diff.dot( _segDir ); + const c = _diff.lengthSq(); + const det = Math.abs( 1 - a01 * a01 ); + let s0, s1, sqrDist, extDet; - } + if ( det > 0 ) { - return true; + // The ray and segment are not parallel. - } + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - const _box$2 = /*@__PURE__*/ new Box3(); - const _v1$6 = /*@__PURE__*/ new Vector3(); - const _v2$3 = /*@__PURE__*/ new Vector3(); + if ( s0 >= 0 ) { - class Sphere { + if ( s1 >= - extDet ) { - constructor( center = new Vector3(), radius = - 1 ) { + if ( s1 <= extDet ) { - this.center = center; - this.radius = radius; + // region 0 + // Minimum at interior points of ray and segment. - } + const invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - set( center, radius ) { + } else { - this.center.copy( center ); - this.radius = radius; + // region 1 - return this; + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - setFromPoints( points, optionalCenter ) { + } else { - const center = this.center; + // region 5 - if ( optionalCenter !== undefined ) { + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - center.copy( optionalCenter ); + } - } else { + } else { - _box$2.setFromPoints( points ).getCenter( center ); + if ( s1 <= - extDet ) { - } + // region 4 - let maxRadiusSq = 0; + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - for ( let i = 0, il = points.length; i < il; i ++ ) { + } else if ( s1 <= extDet ) { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + // region 3 - } + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - this.radius = Math.sqrt( maxRadiusSq ); + } else { - return this; + // region 2 - } + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - copy( sphere ) { + } - this.center.copy( sphere.center ); - this.radius = sphere.radius; + } - return this; + } else { - } + // Ray and segment are parallel. - isEmpty() { + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - return ( this.radius < 0 ); + } - } + if ( optionalPointOnRay ) { - makeEmpty() { + optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); - this.center.set( 0, 0, 0 ); - this.radius = - 1; + } - return this; + if ( optionalPointOnSegment ) { - } + optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); - containsPoint( point ) { + } - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + return sqrDist; } - distanceToPoint( point ) { + intersectSphere( sphere, target ) { - return ( point.distanceTo( this.center ) - this.radius ); + _vector$a.subVectors( sphere.center, this.origin ); + const tca = _vector$a.dot( this.direction ); + const d2 = _vector$a.dot( _vector$a ) - tca * tca; + const radius2 = sphere.radius * sphere.radius; - } + if ( d2 > radius2 ) return null; - intersectsSphere( sphere ) { + const thc = Math.sqrt( radius2 - d2 ); - const radiusSum = this.radius + sphere.radius; + // t0 = first intersect point - entrance on front of sphere + const t0 = tca - thc; - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + // t1 = second intersect point - exit point on back of sphere + const t1 = tca + thc; - } + // test to see if t1 is behind the ray - if so, return null + if ( t1 < 0 ) return null; - intersectsBox( box ) { + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); - return box.intersectsSphere( this ); + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); } - intersectsPlane( plane ) { + intersectsSphere( sphere ) { - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); } - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + distanceToPlane( plane ) { - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); + const denominator = plane.normal.dot( this.direction ); - } + if ( denominator === 0 ) { - return target; + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - } + return 0; - getBoundingBox( target ) { + } - if ( this.isEmpty() ) { + // Null is preferable to undefined since undefined means.... it is undefined - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; + return null; } - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); + const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - return target; + // Return if the ray never intersects the plane - } + return t >= 0 ? t : null; - applyMatrix4( matrix ) { + } - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + intersectPlane( plane, target ) { - return this; + const t = this.distanceToPlane( plane ); - } + if ( t === null ) { - translate( offset ) { + return null; - this.center.add( offset ); + } - return this; + return this.at( t, target ); } - expandByPoint( point ) { + intersectsPlane( plane ) { - if ( this.isEmpty() ) { + // check if the ray lies on the plane first - this.center.copy( point ); + const distToPoint = plane.distanceToPoint( this.origin ); - this.radius = 0; + if ( distToPoint === 0 ) { - return this; + return true; } - _v1$6.subVectors( point, this.center ); + const denominator = plane.normal.dot( this.direction ); - const lengthSq = _v1$6.lengthSq(); + if ( denominator * distToPoint < 0 ) { - if ( lengthSq > ( this.radius * this.radius ) ) { + return true; - // calculate the minimal sphere + } - const length = Math.sqrt( lengthSq ); + // ray origin is behind the plane (and is pointing behind it) - const delta = ( length - this.radius ) * 0.5; + return false; - this.center.addScaledVector( _v1$6, delta / length ); + } - this.radius += delta; + intersectBox( box, target ) { - } + let tmin, tmax, tymin, tymax, tzmin, tzmax; - return this; + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + const origin = this.origin; - union( sphere ) { + if ( invdirx >= 0 ) { - if ( sphere.isEmpty() ) { + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - return this; + } else { + + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; } - if ( this.isEmpty() ) { + if ( invdiry >= 0 ) { - this.copy( sphere ); + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - return this; + } else { + + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; } - if ( this.center.equals( sphere.center ) === true ) { + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - this.radius = Math.max( this.radius, sphere.radius ); + if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; - } else { + if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; - _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); + if ( invdirz >= 0 ) { - this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); + } else { - } + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - return this; + } - } + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - equals( sphere ) { + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - } + //return point closest to the ray (positive side) - clone() { + if ( tmax < 0 ) return null; - return new this.constructor().copy( this ); + return this.at( tmin >= 0 ? tmin : tmax, target ); } - } - - const _vector$a = /*@__PURE__*/ new Vector3(); - const _segCenter = /*@__PURE__*/ new Vector3(); - const _segDir = /*@__PURE__*/ new Vector3(); - const _diff = /*@__PURE__*/ new Vector3(); - - const _edge1 = /*@__PURE__*/ new Vector3(); - const _edge2 = /*@__PURE__*/ new Vector3(); - const _normal$1 = /*@__PURE__*/ new Vector3(); + intersectsBox( box ) { - class Ray { + return this.intersectBox( box, _vector$a ) !== null; - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + } - this.origin = origin; - this.direction = direction; + intersectTriangle( a, b, c, backfaceCulling, target ) { - } + // Compute the offset origin, edges, and normal. - set( origin, direction ) { + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - this.origin.copy( origin ); - this.direction.copy( direction ); + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal$1.crossVectors( _edge1, _edge2 ); - return this; + // 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 ) { - copy( ray ) { + if ( backfaceCulling ) return null; + sign = 1; - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + } else if ( DdN < 0 ) { - return this; + sign = - 1; + DdN = - DdN; - } + } else { - at( t, target ) { + return null; - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + } - } + _diff.subVectors( this.origin, a ); + const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - lookAt( v ) { + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - this.direction.copy( v ).sub( this.origin ).normalize(); + return null; - return this; + } - } + const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - recast( t ) { + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - this.origin.copy( this.at( t, _vector$a ) ); + return null; - return this; + } - } + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - closestPointToPoint( point, target ) { + return null; - target.subVectors( point, this.origin ); + } - const directionDistance = target.dot( this.direction ); + // Line intersects triangle, check if ray does. + const QdN = - sign * _diff.dot( _normal$1 ); - if ( directionDistance < 0 ) { + // t < 0, no intersection + if ( QdN < 0 ) { - return target.copy( this.origin ); + return null; } - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + // Ray intersects triangle. + return this.at( QdN / DdN, target ); } - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } + applyMatrix4( matrix4 ) { - distanceSqToPoint( point ) { + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); + return this; - // point behind the ray + } - if ( directionDistance < 0 ) { + equals( ray ) { - return this.origin.distanceToSquared( point ); + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - } + } - _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + clone() { - return _vector$a.distanceToSquared( point ); + return new this.constructor().copy( this ); } - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // 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 - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); + } - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; + class Matrix4 { - if ( det > 0 ) { + constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - // The ray and segment are not parallel. + Matrix4.prototype.isMatrix4 = true; - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + this.elements = [ - if ( s0 >= 0 ) { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 >= - extDet ) { + ]; - if ( s1 <= extDet ) { + if ( n11 !== undefined ) { - // region 0 - // Minimum at interior points of ray and segment. + this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + } - } else { + } - // region 1 + set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + const te = this.elements; - } + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - } else { + return this; - // region 5 + } - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + identity() { - } + this.set( - } else { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 <= - extDet ) { + ); - // region 4 + return this; - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } else if ( s1 <= extDet ) { + clone() { - // region 3 + return new Matrix4().fromArray( this.elements ); - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } - } else { + copy( m ) { - // region 2 + const te = this.elements; + const me = m.elements; - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - } + return this; - } + } - } else { + copyPosition( m ) { - // Ray and segment are parallel. + const te = this.elements, me = m.elements; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; - } + return this; - if ( optionalPointOnRay ) { + } - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + setFromMatrix3( m ) { - } + const me = m.elements; - if ( optionalPointOnSegment ) { + this.set( - optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); + me[ 0 ], me[ 3 ], me[ 6 ], 0, + me[ 1 ], me[ 4 ], me[ 7 ], 0, + me[ 2 ], me[ 5 ], me[ 8 ], 0, + 0, 0, 0, 1 - } + ); - return sqrDist; + return this; } - intersectSphere( sphere, target ) { + extractBasis( xAxis, yAxis, zAxis ) { - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); - if ( d2 > radius2 ) return null; + return this; - const thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; + makeBasis( xAxis, yAxis, zAxis ) { - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; + 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 + ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + return this; - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); + } - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); + extractRotation( m ) { - } + // this method does not support reflection matrices - intersectsSphere( sphere ) { + const te = this.elements; + const me = m.elements; - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; + + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; + + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; + + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; } - distanceToPlane( plane ) { + makeRotationFromEuler( euler ) { - const denominator = plane.normal.dot( this.direction ); + const te = this.elements; - if ( denominator === 0 ) { + const x = euler.x, y = euler.y, z = euler.z; + const a = Math.cos( x ), b = Math.sin( x ); + const c = Math.cos( y ), d = Math.sin( y ); + const e = Math.cos( z ), f = Math.sin( z ); - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + if ( euler.order === 'XYZ' ) { - return 0; + const ae = a * e, af = a * f, be = b * e, bf = b * f; - } + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - // Null is preferable to undefined since undefined means.... it is undefined + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - return null; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - } + } else if ( euler.order === 'YXZ' ) { - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + const ce = c * e, cf = c * f, de = d * e, df = d * f; - // Return if the ray never intersects the plane + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - return t >= 0 ? t : null; + 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; - intersectPlane( plane, target ) { + } else if ( euler.order === 'ZXY' ) { - const t = this.distanceToPlane( plane ); + const ce = c * e, cf = c * f, de = d * e, df = d * f; - if ( t === null ) { + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - return null; + 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; - return this.at( t, target ); + } else if ( euler.order === 'ZYX' ) { - } + const ae = a * e, af = a * f, be = b * e, bf = b * f; - intersectsPlane( plane ) { + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - // check if the ray lies on the plane first + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - const distToPoint = plane.distanceToPoint( this.origin ); + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - if ( distToPoint === 0 ) { + } else if ( euler.order === 'YZX' ) { - return true; + 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; - const denominator = plane.normal.dot( this.direction ); + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - if ( denominator * distToPoint < 0 ) { + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - return true; + } else if ( euler.order === 'XZY' ) { - } + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // ray origin is behind the plane (and is pointing behind it) + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - return false; + 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; - intersectBox( box, target ) { + } - let tmin, tmax, tymin, tymax, tzmin, tzmax; + // bottom row + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + // last column + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - const origin = this.origin; + return this; - if ( invdirx >= 0 ) { + } - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + makeRotationFromQuaternion( q ) { - } else { + return this.compose( _zero, q, _one ); - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + } - } + lookAt( eye, target, up ) { - if ( invdiry >= 0 ) { + const te = this.elements; - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + _z.subVectors( eye, target ); - } else { + if ( _z.lengthSq() === 0 ) { - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + // eye and target are in the same position - } + _z.z = 1; - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + } - if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; + if ( _x.lengthSq() === 0 ) { - if ( invdirz >= 0 ) { + // up and z are parallel - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + if ( Math.abs( up.z ) === 1 ) { - } else { + _z.x += 0.0001; - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + } else { - } + _z.z += 0.0001; - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + } - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + } - //return point closest to the ray (positive side) + _x.normalize(); + _y.crossVectors( _z, _x ); - if ( tmax < 0 ) return null; + te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; + te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; + te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - return this.at( tmin >= 0 ? tmin : tmax, target ); + return this; } - intersectsBox( box ) { + multiply( m ) { - return this.intersectBox( box, _vector$a ) !== null; + return this.multiplyMatrices( this, m ); } - intersectTriangle( a, b, c, backfaceCulling, target ) { + premultiply( m ) { - // Compute the offset origin, edges, and normal. + return this.multiplyMatrices( m, this ); - // 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 ) { + multiplyMatrices( a, b ) { - if ( backfaceCulling ) return null; - sign = 1; + const ae = a.elements; + const be = b.elements; + const te = this.elements; - } else if ( DdN < 0 ) { + const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - sign = - 1; - DdN = - DdN; + const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - } else { + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - return null; + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - } + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + return this; - return null; + } - } + multiplyScalar( s ) { - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); + const te = this.elements; - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - return null; + return this; - } + } - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + determinant() { - return null; + const te = this.elements; - } + const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - // t < 0, no intersection - if ( QdN < 0 ) { + 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 + ) - return null; + ); - } + } - // Ray intersects triangle. - return this.at( QdN / DdN, target ); + transpose() { - } + const te = this.elements; + let tmp; - applyMatrix4( matrix4 ) { + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; return this; } - equals( ray ) { + setPosition( x, y, z ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + const te = this.elements; - } + if ( x.isVector3 ) { - clone() { + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; - return new this.constructor().copy( this ); + } else { + + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; + + } + + return this; } - } + invert() { - class Matrix4 { + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + const te = this.elements, - constructor() { + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], + n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], + n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], + n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - Matrix4.prototype.isMatrix4 = true; + 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; - this.elements = [ + const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - ]; + const detInv = 1 / det; - } + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - const te = this.elements; + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; return this; } - identity() { - - this.set( + scale( v ) { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + const te = this.elements; + const x = v.x, y = v.y, z = v.z; - ); + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; } - clone() { + getMaxScaleOnAxis() { - return new Matrix4().fromArray( this.elements ); + const te = this.elements; + + const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); } - copy( m ) { + makeTranslation( x, y, z ) { - const te = this.elements; - const me = m.elements; + if ( x.isVector3 ) { - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; + this.set( - return this; + 1, 0, 0, x.x, + 0, 1, 0, x.y, + 0, 0, 1, x.z, + 0, 0, 0, 1 - } + ); - copyPosition( m ) { + } else { - const te = this.elements, me = m.elements; + this.set( - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + } return this; } - setFromMatrix3( m ) { + makeRotationX( theta ) { - const me = m.elements; + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, 0, 0, 0, 1 ); @@ -5940,1504 +6302,1665 @@ } - extractBasis( xAxis, yAxis, zAxis ) { + makeRotationY( theta ) { - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 + + ); return this; } - makeBasis( xAxis, yAxis, zAxis ) { + makeRotationZ( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1 + ); return this; } - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; + makeRotationAxis( axis, angle ) { - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + // Based on http://www.gamedev.net/reference/articles/article1199.asp - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; + const c = Math.cos( angle ); + const s = Math.sin( angle ); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; + this.set( - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + 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 - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + ); return this; } - makeRotationFromEuler( euler ) { - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); + makeScale( x, y, z ) { - if ( euler.order === 'XYZ' ) { + this.set( - const ae = a * e, af = a * f, be = b * e, bf = b * f; + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - 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; + return this; - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; + } - } else if ( euler.order === 'YXZ' ) { + makeShear( xy, xz, yx, yz, zx, zy ) { - const ce = c * e, cf = c * f, de = d * e, df = d * f; + this.set( - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; + 1, yx, zx, 0, + xy, 1, zy, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 - 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; + return this; - } else if ( euler.order === 'ZXY' ) { + } - const ce = c * e, cf = c * f, de = d * e, df = d * f; + compose( position, quaternion, scale ) { - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; + const te = this.elements; - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; + const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; + const sx = scale.x, sy = scale.y, sz = scale.z; - } else if ( euler.order === 'ZYX' ) { + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; - const ae = a * e, af = a * f, be = b * e, bf = b * f; + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; + return this; - } else if ( euler.order === 'YZX' ) { + } - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + decompose( position, quaternion, scale ) { - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; + const te = this.elements; - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; + let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if ( det < 0 ) sx = - sx; - } else if ( euler.order === 'XZY' ) { + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + // scale the rotation part + _m1$2.copy( this ); - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; + _m1$2.elements[ 0 ] *= invSX; + _m1$2.elements[ 1 ] *= invSX; + _m1$2.elements[ 2 ] *= invSX; - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; + _m1$2.elements[ 4 ] *= invSY; + _m1$2.elements[ 5 ] *= invSY; + _m1$2.elements[ 6 ] *= invSY; - } + _m1$2.elements[ 8 ] *= invSZ; + _m1$2.elements[ 9 ] *= invSZ; + _m1$2.elements[ 10 ] *= invSZ; - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + quaternion.setFromRotationMatrix( _m1$2 ); - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + scale.x = sx; + scale.y = sy; + scale.z = sz; return this; } - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); + makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - } + const te = this.elements; + const x = 2 * near / ( right - left ); + const y = 2 * near / ( top - bottom ); - lookAt( eye, target, up ) { + const a = ( right + left ) / ( right - left ); + const b = ( top + bottom ) / ( top - bottom ); - const te = this.elements; + let c, d; - _z.subVectors( eye, target ); + if ( coordinateSystem === WebGLCoordinateSystem ) { - if ( _z.lengthSq() === 0 ) { + c = - ( far + near ) / ( far - near ); + d = ( - 2 * far * near ) / ( far - near ); - // eye and target are in the same position + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - _z.z = 1; + c = - far / ( far - near ); + d = ( - far * near ) / ( far - near ); - } + } else { - _z.normalize(); - _x.crossVectors( up, _z ); + throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); - if ( _x.lengthSq() === 0 ) { + } - // up and z are parallel + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - if ( Math.abs( up.z ) === 1 ) { + return this; - _z.x += 0.0001; + } - } else { + makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - _z.z += 0.0001; - - } + const te = this.elements; + const w = 1.0 / ( right - left ); + const h = 1.0 / ( top - bottom ); + const p = 1.0 / ( far - near ); - _z.normalize(); - _x.crossVectors( up, _z ); + const x = ( right + left ) * w; + const y = ( top + bottom ) * h; - } + let z, zInv; - _x.normalize(); - _y.crossVectors( _z, _x ); + if ( coordinateSystem === WebGLCoordinateSystem ) { - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; + z = ( far + near ) * p; + zInv = - 2 * p; - return this; + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - } + z = near * p; + zInv = - 1 * p; - multiply( m ) { + } else { - return this.multiplyMatrices( this, m ); + throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); - } + } - premultiply( m ) { + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; - return this.multiplyMatrices( m, this ); + return this; } - multiplyMatrices( a, b ) { + equals( matrix ) { - const ae = a.elements; - const be = b.elements; const te = this.elements; + const me = matrix.elements; - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + for ( let i = 0; i < 16; i ++ ) { - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + if ( te[ i ] !== me[ i ] ) return false; - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + } - return this; + return true; } - multiplyScalar( s ) { + fromArray( array, offset = 0 ) { - const te = this.elements; + for ( let i = 0; i < 16; i ++ ) { - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; + this.elements[ i ] = array[ i + offset ]; + + } return this; } - determinant() { + toArray( array = [], offset = 0 ) { const te = this.elements; - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; - 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 - ) + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - ); + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; + + return array; } - transpose() { + } - const te = this.elements; - let tmp; + const _v1$5 = /*@__PURE__*/ new Vector3(); + const _m1$2 = /*@__PURE__*/ new Matrix4(); + const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); + const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); + const _x = /*@__PURE__*/ new Vector3(); + const _y = /*@__PURE__*/ new Vector3(); + const _z = /*@__PURE__*/ new Vector3(); - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; + const _matrix$1 = /*@__PURE__*/ new Matrix4(); + const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; + class Euler { - return this; + constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { + + this.isEuler = true; + + this._x = x; + this._y = y; + this._z = z; + this._order = order; } - setPosition( x, y, z ) { + get x() { - const te = this.elements; + return this._x; - if ( x.isVector3 ) { + } - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; + set x( value ) { - } else { + this._x = value; + this._onChangeCallback(); - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; + } - } + get y() { - return this; + return this._y; } - invert() { + set y( value ) { - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, + this._y = value; + this._onChangeCallback(); - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], + } - t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44, - t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44, - t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44, - t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34; + get z() { - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + return this._z; - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + } - const detInv = 1 / det; + set z( value ) { - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + this._z = value; + this._onChangeCallback(); - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + } - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + get order() { - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + return this._order; - return this; + } + + set order( value ) { + + this._order = value; + this._onChangeCallback(); } - scale( v ) { + set( x, y, z, order = this._order ) { - const te = this.elements; - const x = v.x, y = v.y, z = v.z; + this._x = x; + this._y = y; + this._z = z; + this._order = order; - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; + this._onChangeCallback(); return this; } - getMaxScaleOnAxis() { + clone() { - const te = this.elements; + return new this.constructor( this._x, this._y, this._z, this._order ); - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + } - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + copy( euler ) { + + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; + + this._onChangeCallback(); + + return this; } - makeTranslation( x, y, z ) { + setFromRotationMatrix( m, order = this._order, update = true ) { - this.set( + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + 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': + + this._y = Math.asin( clamp( m13, - 1, 1 ) ); + + if ( Math.abs( m13 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + break; + + case 'YXZ': + + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + + if ( Math.abs( m23 ) < 0.9999999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + break; + + case 'ZXY': + + this._x = Math.asin( clamp( m32, - 1, 1 ) ); + + if ( Math.abs( m32 ) < 0.9999999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + break; + + case 'ZYX': + + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + + if ( Math.abs( m31 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + break; + + case 'YZX': + + this._z = Math.asin( clamp( m21, - 1, 1 ) ); + + if ( Math.abs( m21 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + break; + + case 'XZY': + + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + + if ( Math.abs( m12 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + break; + + default: + + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + + } + + this._order = order; + + if ( update === true ) this._onChangeCallback(); return this; } - makeRotationX( theta ) { + setFromQuaternion( q, order, update ) { - const c = Math.cos( theta ), s = Math.sin( theta ); + _matrix$1.makeRotationFromQuaternion( q ); - this.set( + return this.setFromRotationMatrix( _matrix$1, order, update ); - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + } - ); + setFromVector3( v, order = this._order ) { + + return this.set( v.x, v.y, v.z, order ); + + } + + reorder( newOrder ) { + + // WARNING: this discards revolution information -bhouston + + _quaternion$3.setFromEuler( this ); + + return this.setFromQuaternion( _quaternion$3, newOrder ); + + } + + equals( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + } + + 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; } - makeRotationY( theta ) { + toArray( array = [], offset = 0 ) { - const c = Math.cos( theta ), s = Math.sin( theta ); + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; - this.set( + return array; - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + } - ); + _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 ) { + + this.mask = ( 1 << channel | 0 ) >>> 0; + + } + + enable( channel ) { + + this.mask |= 1 << channel | 0; + + } + + enableAll() { + + this.mask = 0xffffffff | 0; + + } + + toggle( channel ) { + + this.mask ^= 1 << channel | 0; + + } + + disable( channel ) { + + this.mask &= ~ ( 1 << channel | 0 ); + + } + + disableAll() { + + this.mask = 0; + + } + + test( layers ) { + + return ( this.mask & layers.mask ) !== 0; + + } + + isEnabled( channel ) { + + return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + + } + + } + + let _object3DId = 0; + + const _v1$4 = /*@__PURE__*/ new Vector3(); + const _q1 = /*@__PURE__*/ new Quaternion(); + const _m1$1 = /*@__PURE__*/ new Matrix4(); + const _target = /*@__PURE__*/ new Vector3(); + + const _position$3 = /*@__PURE__*/ new Vector3(); + const _scale$2 = /*@__PURE__*/ new Vector3(); + const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + + const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); + const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + + const _addedEvent = { type: 'added' }; + const _removedEvent = { type: 'removed' }; + + class Object3D extends EventDispatcher { + + constructor() { + + super(); + + this.isObject3D = true; + + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = Object3D.DEFAULT_UP.clone(); + + const position = new Vector3(); + const rotation = new Euler(); + const quaternion = new Quaternion(); + const scale = new Vector3( 1, 1, 1 ); + + function onRotationChange() { + + quaternion.setFromEuler( rotation, false ); + + } + + function onQuaternionChange() { + + rotation.setFromQuaternion( quaternion, undefined, false ); + + } + + 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() + } + } ); - return this; + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); - } + this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; - makeRotationZ( theta ) { + this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer + this.matrixWorldNeedsUpdate = false; - const c = Math.cos( theta ), s = Math.sin( theta ); + this.layers = new Layers(); + this.visible = true; - this.set( + this.castShadow = false; + this.receiveShadow = false; - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + this.frustumCulled = true; + this.renderOrder = 0; - ); + this.animations = []; - return this; + this.userData = {}; } - makeRotationAxis( axis, angle ) { - - // Based on http://www.gamedev.net/reference/articles/article1199.asp - - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; - - this.set( - - tx * x + c, tx * y - s * z, tx * z + s * y, 0, - tx * y + s * z, ty * y + c, ty * z - s * x, 0, - tx * z - s * y, ty * z + s * x, t * z * z + c, 0, - 0, 0, 0, 1 - - ); + onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - return this; + onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - } + onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - makeScale( x, y, z ) { + onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - this.set( + applyMatrix4( matrix ) { - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + if ( this.matrixAutoUpdate ) this.updateMatrix(); - ); + this.matrix.premultiply( matrix ); - return this; + this.matrix.decompose( this.position, this.quaternion, this.scale ); } - makeShear( xy, xz, yx, yz, zx, zy ) { - - this.set( - - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 + applyQuaternion( q ) { - ); + this.quaternion.premultiply( q ); return this; } - compose( position, quaternion, scale ) { - - const te = this.elements; - - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; - - const sx = scale.x, sy = scale.y, sz = scale.z; + setRotationFromAxisAngle( axis, angle ) { - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; + // assumes axis is normalized - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; + this.quaternion.setFromAxisAngle( axis, angle ); - 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; + setRotationFromEuler( euler ) { - return this; + this.quaternion.setFromEuler( euler, true ); } - decompose( position, quaternion, scale ) { + setRotationFromMatrix( m ) { - const te = this.elements; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + this.quaternion.setFromRotationMatrix( m ); - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; + } - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; + setRotationFromQuaternion( q ) { - // scale the rotation part - _m1$2.copy( this ); + // assumes q is normalized - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; + this.quaternion.copy( q ); - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; + } - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; + rotateOnAxis( axis, angle ) { - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; + // rotate object on axis in object space + // axis is assumed to be normalized - quaternion.setFromRotationMatrix( _m1$2 ); + _q1.setFromAxisAngle( axis, angle ); - scale.x = sx; - scale.y = sy; - scale.z = sz; + this.quaternion.multiply( _q1 ); return this; } - makePerspective( left, right, top, bottom, near, far ) { + rotateOnWorldAxis( axis, angle ) { - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - const c = - ( far + near ) / ( far - near ); - const d = - 2 * far * near / ( far - near ); + _q1.setFromAxisAngle( axis, angle ); - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + this.quaternion.premultiply( _q1 ); return this; } - makeOrthographic( left, right, top, bottom, near, far ) { + rotateX( angle ) { - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); + return this.rotateOnAxis( _xAxis, angle ); - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - const z = ( far + near ) * p; + } - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + rotateY( angle ) { - return this; + return this.rotateOnAxis( _yAxis, angle ); } - equals( matrix ) { + rotateZ( angle ) { - const te = this.elements; - const me = matrix.elements; + return this.rotateOnAxis( _zAxis, angle ); - for ( let i = 0; i < 16; i ++ ) { + } - if ( te[ i ] !== me[ i ] ) return false; + translateOnAxis( axis, distance ) { - } + // translate object by distance along axis in object space + // axis is assumed to be normalized - return true; + _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + + this.position.add( _v1$4.multiplyScalar( distance ) ); + + return this; } - fromArray( array, offset = 0 ) { + translateX( distance ) { - for ( let i = 0; i < 16; i ++ ) { + return this.translateOnAxis( _xAxis, distance ); - this.elements[ i ] = array[ i + offset ]; + } - } + translateY( distance ) { - return this; + return this.translateOnAxis( _yAxis, distance ); } - toArray( array = [], offset = 0 ) { - - const te = this.elements; + translateZ( distance ) { - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; + return this.translateOnAxis( _zAxis, distance ); - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; + } - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; + localToWorld( vector ) { - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; + this.updateWorldMatrix( true, false ); - return array; + return vector.applyMatrix4( this.matrixWorld ); } - } + worldToLocal( vector ) { - const _v1$5 = /*@__PURE__*/ new Vector3(); - const _m1$2 = /*@__PURE__*/ new Matrix4(); - const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); - const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); - const _x = /*@__PURE__*/ new Vector3(); - const _y = /*@__PURE__*/ new Vector3(); - const _z = /*@__PURE__*/ new Vector3(); + this.updateWorldMatrix( true, false ); - const _matrix$1 = /*@__PURE__*/ new Matrix4(); - const _quaternion$3 = /*@__PURE__*/ new Quaternion(); + return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - class Euler { + } - constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { + lookAt( x, y, z ) { - this.isEuler = true; + // This method does not support objects having non-uniformly-scaled parent(s) - this._x = x; - this._y = y; - this._z = z; - this._order = order; + if ( x.isVector3 ) { - } + _target.copy( x ); - get x() { + } else { - return this._x; + _target.set( x, y, z ); + + } - } + const parent = this.parent; - set x( value ) { + this.updateWorldMatrix( true, false ); - this._x = value; - this._onChangeCallback(); + _position$3.setFromMatrixPosition( this.matrixWorld ); - } + if ( this.isCamera || this.isLight ) { - get y() { + _m1$1.lookAt( _position$3, _target, this.up ); - return this._y; + } else { - } + _m1$1.lookAt( _target, _position$3, this.up ); - set y( value ) { + } - this._y = value; - this._onChangeCallback(); + this.quaternion.setFromRotationMatrix( _m1$1 ); - } + if ( parent ) { - get z() { + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.invert() ); - return this._z; + } } - set z( value ) { - - this._z = value; - this._onChangeCallback(); + add( object ) { - } + if ( arguments.length > 1 ) { - get order() { + for ( let i = 0; i < arguments.length; i ++ ) { - return this._order; + this.add( arguments[ i ] ); - } + } - set order( value ) { + return this; - this._order = value; - this._onChangeCallback(); + } - } + if ( object === this ) { - set( x, y, z, order = this._order ) { + console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); + return this; - this._x = x; - this._y = y; - this._z = z; - this._order = order; + } - this._onChangeCallback(); + if ( object && object.isObject3D ) { - return this; + if ( object.parent !== null ) { - } + object.parent.remove( object ); - clone() { + } - return new this.constructor( this._x, this._y, this._z, this._order ); + object.parent = this; + this.children.push( object ); - } + object.dispatchEvent( _addedEvent ); - copy( euler ) { + } else { - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - this._onChangeCallback(); + } return this; } - setFromRotationMatrix( m, order = this._order, update = true ) { - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + remove( object ) { - 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 ]; + if ( arguments.length > 1 ) { - switch ( order ) { + for ( let i = 0; i < arguments.length; i ++ ) { - case 'XYZ': + this.remove( arguments[ i ] ); - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + } - if ( Math.abs( m13 ) < 0.9999999 ) { + return this; - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + } - } else { + const index = this.children.indexOf( object ); - this._x = Math.atan2( m32, m22 ); - this._z = 0; + if ( index !== - 1 ) { - } + object.parent = null; + this.children.splice( index, 1 ); - break; + object.dispatchEvent( _removedEvent ); - case 'YXZ': + } - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + return this; - if ( Math.abs( m23 ) < 0.9999999 ) { + } - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + removeFromParent() { - } else { + const parent = this.parent; - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + if ( parent !== null ) { - } + parent.remove( this ); - break; + } - case 'ZXY': + return this; - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + } - if ( Math.abs( m32 ) < 0.9999999 ) { + clear() { - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + return this.remove( ... this.children ); - } else { + } - this._y = 0; - this._z = Math.atan2( m21, m11 ); + attach( object ) { - } + // adds object as a child of this, while maintaining the object's world transform - break; + // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - case 'ZYX': + this.updateWorldMatrix( true, false ); - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + _m1$1.copy( this.matrixWorld ).invert(); - if ( Math.abs( m31 ) < 0.9999999 ) { + if ( object.parent !== null ) { - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + object.parent.updateWorldMatrix( true, false ); - } else { + _m1$1.multiply( object.parent.matrixWorld ); - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + } - } + object.applyMatrix4( _m1$1 ); - break; + this.add( object ); - case 'YZX': + object.updateWorldMatrix( false, true ); - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + return this; - if ( Math.abs( m21 ) < 0.9999999 ) { + } - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + getObjectById( id ) { - } else { + return this.getObjectByProperty( 'id', id ); - this._x = 0; - this._y = Math.atan2( m13, m33 ); + } - } + getObjectByName( name ) { - break; + return this.getObjectByProperty( 'name', name ); - case 'XZY': + } - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + getObjectByProperty( name, value ) { - if ( Math.abs( m12 ) < 0.9999999 ) { + if ( this[ name ] === value ) return this; - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + for ( let i = 0, l = this.children.length; i < l; i ++ ) { - } else { + const child = this.children[ i ]; + const object = child.getObjectByProperty( name, value ); - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + if ( object !== undefined ) { - } + return object; - break; + } - default: + } - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + return undefined; - } + } - this._order = order; + getObjectsByProperty( name, value, result = [] ) { - if ( update === true ) this._onChangeCallback(); + if ( this[ name ] === value ) result.push( this ); - return this; + const children = this.children; - } + for ( let i = 0, l = children.length; i < l; i ++ ) { - setFromQuaternion( q, order, update ) { + children[ i ].getObjectsByProperty( name, value, result ); - _matrix$1.makeRotationFromQuaternion( q ); + } - return this.setFromRotationMatrix( _matrix$1, order, update ); + return result; } - setFromVector3( v, order = this._order ) { + getWorldPosition( target ) { - return this.set( v.x, v.y, v.z, order ); + this.updateWorldMatrix( true, false ); + + return target.setFromMatrixPosition( this.matrixWorld ); } - reorder( newOrder ) { + getWorldQuaternion( target ) { - // WARNING: this discards revolution information -bhouston + this.updateWorldMatrix( true, false ); - _quaternion$3.setFromEuler( this ); + this.matrixWorld.decompose( _position$3, target, _scale$2 ); - return this.setFromQuaternion( _quaternion$3, newOrder ); + return target; } - equals( euler ) { + getWorldScale( target ) { - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + this.updateWorldMatrix( true, false ); + + this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + + return target; } - fromArray( array ) { + getWorldDirection( target ) { - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + this.updateWorldMatrix( true, false ); - this._onChangeCallback(); + const e = this.matrixWorld.elements; - return this; + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); } - toArray( array = [], offset = 0 ) { + raycast( /* raycaster, intersects */ ) {} - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + traverse( callback ) { - return array; + callback( this ); - } + const children = this.children; - _onChange( callback ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - this._onChangeCallback = callback; + children[ i ].traverse( callback ); - return this; + } } - _onChangeCallback() {} + traverseVisible( callback ) { - *[ Symbol.iterator ]() { + if ( this.visible === false ) return; - yield this._x; - yield this._y; - yield this._z; - yield this._order; + callback( this ); - } + const children = this.children; - // @deprecated since r138, 02cf0df1cb4575d5842fef9c85bb5a89fe020d53 + for ( let i = 0, l = children.length; i < l; i ++ ) { - toVector3() { + children[ i ].traverseVisible( callback ); - console.error( 'THREE.Euler: .toVector3() has been removed. Use Vector3.setFromEuler() instead' ); + } } - } + traverseAncestors( callback ) { - Euler.DefaultOrder = 'XYZ'; - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; + const parent = this.parent; - class Layers { + if ( parent !== null ) { - constructor() { + callback( parent ); - this.mask = 1 | 0; + parent.traverseAncestors( callback ); + + } } - set( channel ) { + updateMatrix() { - this.mask = ( 1 << channel | 0 ) >>> 0; + this.matrix.compose( this.position, this.quaternion, this.scale ); - } + this.matrixWorldNeedsUpdate = true; - enable( channel ) { + } - this.mask |= 1 << channel | 0; + updateMatrixWorld( force ) { - } + if ( this.matrixAutoUpdate ) this.updateMatrix(); - enableAll() { + if ( this.matrixWorldNeedsUpdate || force ) { - this.mask = 0xffffffff | 0; + if ( this.parent === null ) { - } + this.matrixWorld.copy( this.matrix ); - toggle( channel ) { + } else { - this.mask ^= 1 << channel | 0; + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - } + } - disable( channel ) { + this.matrixWorldNeedsUpdate = false; - this.mask &= ~ ( 1 << channel | 0 ); + force = true; - } + } - disableAll() { + // update children - this.mask = 0; + const children = this.children; - } + for ( let i = 0, l = children.length; i < l; i ++ ) { - test( layers ) { + const child = children[ i ]; - return ( this.mask & layers.mask ) !== 0; + if ( child.matrixWorldAutoUpdate === true || force === true ) { - } + child.updateMatrixWorld( force ); - isEnabled( channel ) { + } - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + } } - } + updateWorldMatrix( updateParents, updateChildren ) { - let _object3DId = 0; + const parent = this.parent; - const _v1$4 = /*@__PURE__*/ new Vector3(); - const _q1 = /*@__PURE__*/ new Quaternion(); - const _m1$1 = /*@__PURE__*/ new Matrix4(); - const _target = /*@__PURE__*/ new Vector3(); + if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - const _position$3 = /*@__PURE__*/ new Vector3(); - const _scale$2 = /*@__PURE__*/ new Vector3(); - const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + parent.updateWorldMatrix( true, false ); - const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); - const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + } - const _addedEvent = { type: 'added' }; - const _removedEvent = { type: 'removed' }; + if ( this.matrixAutoUpdate ) this.updateMatrix(); - class Object3D extends EventDispatcher { + if ( this.parent === null ) { - constructor() { + this.matrixWorld.copy( this.matrix ); - super(); + } else { - this.isObject3D = true; + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + } - this.uuid = generateUUID(); + // update children - this.name = ''; - this.type = 'Object3D'; + if ( updateChildren === true ) { - this.parent = null; - this.children = []; + const children = this.children; - this.up = Object3D.DefaultUp.clone(); + for ( let i = 0, l = children.length; i < l; i ++ ) { - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); + const child = children[ i ]; - function onRotationChange() { + if ( child.matrixWorldAutoUpdate === true ) { - quaternion.setFromEuler( rotation, false ); + child.updateWorldMatrix( false, true ); + + } + + } } - function onQuaternionChange() { + } - rotation.setFromQuaternion( quaternion, undefined, false ); + toJSON( meta ) { - } + // meta is a string when called from JSON.stringify + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); + const output = {}; - 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() - } - } ); + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - this.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {}, + skeletons: {}, + animations: {}, + nodes: {} + }; - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + output.metadata = { + version: 4.6, + type: 'Object', + generator: 'Object3D.toJSON' + }; - this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer + } - this.layers = new Layers(); - this.visible = true; + // standard Object3D serialization - this.castShadow = false; - this.receiveShadow = false; + const object = {}; - this.frustumCulled = true; - this.renderOrder = 0; + object.uuid = this.uuid; + object.type = this.type; - this.animations = []; + if ( this.name !== '' ) object.name = this.name; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + if ( this.frustumCulled === false ) object.frustumCulled = false; + if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; + if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; - this.userData = {}; + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); + object.up = this.up.toArray(); - } + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} + // object specific properties - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} + if ( this.isInstancedMesh ) { - applyMatrix4( matrix ) { + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); + if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - if ( this.matrixAutoUpdate ) this.updateMatrix(); + } - this.matrix.premultiply( matrix ); + if ( this.isBatchedMesh ) { - this.matrix.decompose( this.position, this.quaternion, this.scale ); + object.type = 'BatchedMesh'; + object.perObjectFrustumCulled = this.perObjectFrustumCulled; + object.sortObjects = this.sortObjects; - } + object.drawRanges = this._drawRanges; + object.reservedRanges = this._reservedRanges; - applyQuaternion( q ) { + 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(), - this.quaternion.premultiply( q ); + sphereInitialized: bound.sphereInitialized, + sphereRadius: bound.sphere.radius, + sphereCenter: bound.sphere.center.toArray() + } ) ); - return this; + object.maxGeometryCount = this._maxGeometryCount; + object.maxVertexCount = this._maxVertexCount; + object.maxIndexCount = this._maxIndexCount; - } + object.geometryInitialized = this._geometryInitialized; + object.geometryCount = this._geometryCount; - setRotationFromAxisAngle( axis, angle ) { + object.matricesTexture = this._matricesTexture.toJSON( meta ); - // assumes axis is normalized + if ( this.boundingSphere !== null ) { - this.quaternion.setFromAxisAngle( axis, angle ); + object.boundingSphere = { + center: object.boundingSphere.center.toArray(), + radius: object.boundingSphere.radius + }; - } + } - setRotationFromEuler( euler ) { + if ( this.boundingBox !== null ) { - this.quaternion.setFromEuler( euler, true ); + object.boundingBox = { + min: object.boundingBox.min.toArray(), + max: object.boundingBox.max.toArray() + }; - } + } - setRotationFromMatrix( m ) { + } - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + // - this.quaternion.setFromRotationMatrix( m ); + function serialize( library, element ) { - } + if ( library[ element.uuid ] === undefined ) { + + library[ element.uuid ] = element.toJSON( meta ); + + } - setRotationFromQuaternion( q ) { + return element.uuid; - // assumes q is normalized + } - this.quaternion.copy( q ); + if ( this.isScene ) { - } + if ( this.background ) { - rotateOnAxis( axis, angle ) { + if ( this.background.isColor ) { - // rotate object on axis in object space - // axis is assumed to be normalized + object.background = this.background.toJSON(); - _q1.setFromAxisAngle( axis, angle ); + } else if ( this.background.isTexture ) { - this.quaternion.multiply( _q1 ); + object.background = this.background.toJSON( meta ).uuid; - return this; + } - } + } - rotateOnWorldAxis( axis, angle ) { + if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + object.environment = this.environment.toJSON( meta ).uuid; - _q1.setFromAxisAngle( axis, angle ); + } - this.quaternion.premultiply( _q1 ); + } else if ( this.isMesh || this.isLine || this.isPoints ) { - return this; + object.geometry = serialize( meta.geometries, this.geometry ); - } + const parameters = this.geometry.parameters; - rotateX( angle ) { + if ( parameters !== undefined && parameters.shapes !== undefined ) { - return this.rotateOnAxis( _xAxis, angle ); + const shapes = parameters.shapes; - } + if ( Array.isArray( shapes ) ) { - rotateY( angle ) { + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - return this.rotateOnAxis( _yAxis, angle ); + const shape = shapes[ i ]; - } + serialize( meta.shapes, shape ); - rotateZ( angle ) { + } - return this.rotateOnAxis( _zAxis, angle ); + } else { - } + serialize( meta.shapes, shapes ); - translateOnAxis( axis, distance ) { + } - // translate object by distance along axis in object space - // axis is assumed to be normalized + } - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + } - this.position.add( _v1$4.multiplyScalar( distance ) ); + if ( this.isSkinnedMesh ) { - return this; + object.bindMode = this.bindMode; + object.bindMatrix = this.bindMatrix.toArray(); - } + if ( this.skeleton !== undefined ) { - translateX( distance ) { + serialize( meta.skeletons, this.skeleton ); - return this.translateOnAxis( _xAxis, distance ); + object.skeleton = this.skeleton.uuid; - } + } - translateY( distance ) { + } - return this.translateOnAxis( _yAxis, distance ); + if ( this.material !== undefined ) { - } + if ( Array.isArray( this.material ) ) { - translateZ( distance ) { + const uuids = []; - return this.translateOnAxis( _zAxis, distance ); + for ( let i = 0, l = this.material.length; i < l; i ++ ) { - } + uuids.push( serialize( meta.materials, this.material[ i ] ) ); - localToWorld( vector ) { + } - return vector.applyMatrix4( this.matrixWorld ); + object.material = uuids; - } + } else { - worldToLocal( vector ) { + object.material = serialize( meta.materials, this.material ); - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); + } - } + } - lookAt( x, y, z ) { + // - // This method does not support objects having non-uniformly-scaled parent(s) + if ( this.children.length > 0 ) { - if ( x.isVector3 ) { + object.children = []; - _target.copy( x ); + for ( let i = 0; i < this.children.length; i ++ ) { - } else { + object.children.push( this.children[ i ].toJSON( meta ).object ); - _target.set( x, y, z ); + } } - const parent = this.parent; + // - this.updateWorldMatrix( true, false ); + if ( this.animations.length > 0 ) { - _position$3.setFromMatrixPosition( this.matrixWorld ); + object.animations = []; - if ( this.isCamera || this.isLight ) { + for ( let i = 0; i < this.animations.length; i ++ ) { - _m1$1.lookAt( _position$3, _target, this.up ); + const animation = this.animations[ i ]; - } else { + object.animations.push( serialize( meta.animations, animation ) ); - _m1$1.lookAt( _target, _position$3, this.up ); + } } - this.quaternion.setFromRotationMatrix( _m1$1 ); + if ( isRootObject ) { - if ( parent ) { + const geometries = extractFromCache( meta.geometries ); + const materials = extractFromCache( meta.materials ); + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const shapes = extractFromCache( meta.shapes ); + const skeletons = extractFromCache( meta.skeletons ); + const animations = extractFromCache( meta.animations ); + const nodes = extractFromCache( meta.nodes ); - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; + if ( skeletons.length > 0 ) output.skeletons = skeletons; + if ( animations.length > 0 ) output.animations = animations; + if ( nodes.length > 0 ) output.nodes = nodes; } - } + output.object = object; - add( object ) { + return output; - if ( arguments.length > 1 ) { + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - for ( let i = 0; i < arguments.length; i ++ ) { + const values = []; + for ( const key in cache ) { - this.add( arguments[ i ] ); + const data = cache[ key ]; + delete data.metadata; + values.push( data ); } - return this; - - } - - if ( object === this ) { - - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; + return values; } - if ( object && object.isObject3D ) { - - if ( object.parent !== null ) { - - object.parent.remove( object ); + } - } + clone( recursive ) { - object.parent = this; - this.children.push( object ); + return new this.constructor().copy( this, recursive ); - object.dispatchEvent( _addedEvent ); + } - } else { + copy( source, recursive = true ) { - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); + this.name = source.name; - } + this.up.copy( source.up ); - return this; + 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 ); - remove( object ) { + this.matrixAutoUpdate = source.matrixAutoUpdate; - if ( arguments.length > 1 ) { + this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - for ( let i = 0; i < arguments.length; i ++ ) { + this.layers.mask = source.layers.mask; + this.visible = source.visible; - this.remove( arguments[ i ] ); + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; - } + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - return this; + this.animations = source.animations.slice(); - } + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - const index = this.children.indexOf( object ); + if ( recursive === true ) { - if ( index !== - 1 ) { + for ( let i = 0; i < source.children.length; i ++ ) { - object.parent = null; - this.children.splice( index, 1 ); + const child = source.children[ i ]; + this.add( child.clone() ); - object.dispatchEvent( _removedEvent ); + } } @@ -7445,872 +7968,969 @@ } - removeFromParent() { - - const parent = this.parent; + } - if ( parent !== null ) { + Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; + Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; - parent.remove( this ); + const _v0$1 = /*@__PURE__*/ new Vector3(); + const _v1$3 = /*@__PURE__*/ new Vector3(); + const _v2$2 = /*@__PURE__*/ new Vector3(); + const _v3$1 = /*@__PURE__*/ new Vector3(); - } + const _vab = /*@__PURE__*/ new Vector3(); + const _vac = /*@__PURE__*/ new Vector3(); + const _vbc = /*@__PURE__*/ new Vector3(); + const _vap = /*@__PURE__*/ new Vector3(); + const _vbp = /*@__PURE__*/ new Vector3(); + const _vcp = /*@__PURE__*/ new Vector3(); - return this; + let warnedGetUV = false; - } + class Triangle { - clear() { + constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - for ( let i = 0; i < this.children.length; i ++ ) { + this.a = a; + this.b = b; + this.c = c; - const object = this.children[ i ]; + } - object.parent = null; + static getNormal( a, b, c, target ) { - object.dispatchEvent( _removedEvent ); + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); - } + const targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - this.children.length = 0; + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); - return this; + } + return target.set( 0, 0, 0 ); } - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static getBarycoord( point, a, b, c, target ) { - this.updateWorldMatrix( true, false ); + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$2.subVectors( point, a ); - _m1$1.copy( this.matrixWorld ).invert(); + const dot00 = _v0$1.dot( _v0$1 ); + const dot01 = _v0$1.dot( _v1$3 ); + const dot02 = _v0$1.dot( _v2$2 ); + const dot11 = _v1$3.dot( _v1$3 ); + const dot12 = _v1$3.dot( _v2$2 ); - if ( object.parent !== null ) { + const denom = ( dot00 * dot11 - dot01 * dot01 ); - object.parent.updateWorldMatrix( true, false ); + // collinear or singular triangle + if ( denom === 0 ) { - _m1$1.multiply( object.parent.matrixWorld ); + target.set( 0, 0, 0 ); + return null; } - object.applyMatrix4( _m1$1 ); + const invDenom = 1 / denom; + const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - this.add( object ); + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - object.updateWorldMatrix( false, true ); + } - return this; + static containsPoint( point, a, b, c ) { - } + // if the triangle is degenerate then we can't contain a point + if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) { - getObjectById( id ) { + return false; - return this.getObjectByProperty( 'id', id ); + } + + return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); } - getObjectByName( name ) { + static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151 - return this.getObjectByProperty( 'name', name ); + if ( warnedGetUV === false ) { - } + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - getObjectByProperty( name, value ) { + warnedGetUV = true; - if ( this[ name ] === value ) return this; + } - for ( let i = 0, l = this.children.length; i < l; i ++ ) { + return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target ); - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); + } - if ( object !== undefined ) { + static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { - return object; + if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) { - } + target.x = 0; + target.y = 0; + if ( 'z' in target ) target.z = 0; + if ( 'w' in target ) target.w = 0; + return null; } - return undefined; + target.setScalar( 0 ); + target.addScaledVector( v1, _v3$1.x ); + target.addScaledVector( v2, _v3$1.y ); + target.addScaledVector( v3, _v3$1.z ); + + return target; } - getWorldPosition( target ) { + static isFrontFacing( a, b, c, direction ) { - this.updateWorldMatrix( true, false ); + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); - return target.setFromMatrixPosition( this.matrixWorld ); + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; } - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); + set( a, b, c ) { - this.matrixWorld.decompose( _position$3, target, _scale$2 ); + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - return target; + return this; } - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); + setFromPointsAndIndices( points, i0, i1, i2 ) { - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); - return target; + return this; } - getWorldDirection( target ) { + setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - this.updateWorldMatrix( true, false ); + this.a.fromBufferAttribute( attribute, i0 ); + this.b.fromBufferAttribute( attribute, i1 ); + this.c.fromBufferAttribute( attribute, i2 ); - const e = this.matrixWorld.elements; + return this; - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + } + + clone() { + + return new this.constructor().copy( this ); } - raycast( /* raycaster, intersects */ ) {} + copy( triangle ) { - traverse( callback ) { + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - callback( this ); + return this; - const children = this.children; + } - for ( let i = 0, l = children.length; i < l; i ++ ) { + getArea() { - children[ i ].traverse( callback ); + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); - } + return _v0$1.cross( _v1$3 ).length() * 0.5; } - traverseVisible( callback ) { + getMidpoint( target ) { - if ( this.visible === false ) return; + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); - callback( this ); + } - const children = this.children; + getNormal( target ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + return Triangle.getNormal( this.a, this.b, this.c, target ); - children[ i ].traverseVisible( callback ); + } - } + getPlane( target ) { - } + return target.setFromCoplanarPoints( this.a, this.b, this.c ); - traverseAncestors( callback ) { + } - const parent = this.parent; + getBarycoord( point, target ) { - if ( parent !== null ) { + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); - callback( parent ); + } - parent.traverseAncestors( callback ); + getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151 - } + if ( warnedGetUV === false ) { - } + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - updateMatrix() { + warnedGetUV = true; - this.matrix.compose( this.position, this.quaternion, this.scale ); + } - this.matrixWorldNeedsUpdate = true; + return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); } - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); + getInterpolation( point, v1, v2, v3, target ) { - if ( this.matrixWorldNeedsUpdate || force ) { + return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); - if ( this.parent === null ) { + } - this.matrixWorld.copy( this.matrix ); + containsPoint( point ) { - } else { + return Triangle.containsPoint( point, this.a, this.b, this.c ); - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + } - } + isFrontFacing( direction ) { - this.matrixWorldNeedsUpdate = false; + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); - force = true; + } - } + intersectsBox( box ) { - // update children + return box.intersectsTriangle( this ); - const children = this.children; + } - for ( let i = 0, l = children.length; i < l; i ++ ) { + closestPointToPoint( p, target ) { - const child = children[ i ]; + const a = this.a, b = this.b, c = this.c; + let v, w; - if ( child.matrixWorldAutoUpdate === true || force === true ) { + // algorithm thanks to Real-Time Collision Detection by Christer Ericson, + // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., + // under the accompanying license; see chapter 5.1.5 for detailed explanation. + // basically, we're distinguishing which of the voronoi regions of the triangle + // the point lies in with the minimum amount of redundant computation. - child.updateMatrixWorld( force ); + _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 ) { - } + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); } - } + _vbp.subVectors( p, b ); + const d3 = _vab.dot( _vbp ); + const d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { - updateWorldMatrix( updateParents, updateChildren ) { + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); - const parent = this.parent; + } - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { + const vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - parent.updateWorldMatrix( true, false ); + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( _vab, v ); } - if ( this.matrixAutoUpdate ) this.updateMatrix(); + _vcp.subVectors( p, c ); + const d5 = _vab.dot( _vcp ); + const d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - if ( this.parent === null ) { + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); - this.matrixWorld.copy( this.matrix ); + } - } else { + const vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); } - // update children - - if ( updateChildren === true ) { - - const children = this.children; + const va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + _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 - const child = children[ i ]; + } - if ( child.matrixWorldAutoUpdate === true ) { + // face region + const denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; - child.updateWorldMatrix( false, true ); + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - } + } - } + equals( triangle ) { - } + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); } - toJSON( meta ) { + } - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - const output = {}; + const _hslA = { h: 0, s: 0, l: 0 }; + const _hslB = { h: 0, s: 0, l: 0 }; - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + function hue2rgb( p, q, t ) { - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; + 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; - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; + } - } + class Color { - // standard Object3D serialization + constructor( r, g, b ) { - const object = {}; + this.isColor = true; - object.uuid = this.uuid; - object.type = this.type; + this.r = 1; + this.g = 1; + this.b = 1; - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + return this.set( r, g, b ); - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); + } - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + set( r, g, b ) { - // object specific properties + if ( g === undefined && b === undefined ) { - if ( this.isInstancedMesh ) { + // r is THREE.Color, hex or string - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); + const value = r; - } + if ( value && value.isColor ) { - // + this.copy( value ); - function serialize( library, element ) { + } else if ( typeof value === 'number' ) { - if ( library[ element.uuid ] === undefined ) { + this.setHex( value ); - library[ element.uuid ] = element.toJSON( meta ); + } else if ( typeof value === 'string' ) { + + this.setStyle( value ); } - return element.uuid; + } else { - } + this.setRGB( r, g, b ); - if ( this.isScene ) { + } - if ( this.background ) { + return this; - if ( this.background.isColor ) { + } - object.background = this.background.toJSON(); + setScalar( scalar ) { - } else if ( this.background.isTexture ) { + this.r = scalar; + this.g = scalar; + this.b = scalar; - object.background = this.background.toJSON( meta ).uuid; + return this; - } + } - } + setHex( hex, colorSpace = SRGBColorSpace ) { - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { + hex = Math.floor( hex ); - object.environment = this.environment.toJSON( meta ).uuid; + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - } + ColorManagement.toWorkingColorSpace( this, colorSpace ); - } else if ( this.isMesh || this.isLine || this.isPoints ) { + return this; - object.geometry = serialize( meta.geometries, this.geometry ); + } - const parameters = this.geometry.parameters; + setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { - if ( parameters !== undefined && parameters.shapes !== undefined ) { + this.r = r; + this.g = g; + this.b = b; - const shapes = parameters.shapes; + ColorManagement.toWorkingColorSpace( this, colorSpace ); - if ( Array.isArray( shapes ) ) { + return this; - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + } - const shape = shapes[ i ]; + setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { - serialize( meta.shapes, shape ); + // h,s,l ranges are in 0.0 - 1.0 + h = euclideanModulo( h, 1 ); + s = clamp( s, 0, 1 ); + l = clamp( l, 0, 1 ); - } + if ( s === 0 ) { - } else { + this.r = this.g = this.b = l; - serialize( meta.shapes, shapes ); + } else { - } + const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + const q = ( 2 * l ) - p; - } + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); } - if ( this.isSkinnedMesh ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); + return this; - if ( this.skeleton !== undefined ) { + } - serialize( meta.skeletons, this.skeleton ); + setStyle( style, colorSpace = SRGBColorSpace ) { - object.skeleton = this.skeleton.uuid; + function handleAlpha( string ) { + + if ( string === undefined ) return; + + if ( parseFloat( string ) < 1 ) { + + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); } } - if ( this.material !== undefined ) { - if ( Array.isArray( this.material ) ) { + let m; - const uuids = []; + if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { - for ( let i = 0, l = this.material.length; i < l; i ++ ) { + // rgb / hsl - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + let color; + const name = m[ 1 ]; + const components = m[ 2 ]; - } + switch ( name ) { - object.material = uuids; + case 'rgb': + case 'rgba': - } else { + if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - object.material = serialize( meta.materials, this.material ); + // 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 ( this.children.length > 0 ) { + if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - object.children = []; + // rgb(100%,0%,0%) rgba(100%,0%,0%,0.5) - for ( let i = 0; i < this.children.length; i ++ ) { + handleAlpha( color[ 4 ] ); - object.children.push( this.children[ i ].toJSON( meta ).object ); + 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 ( this.animations.length > 0 ) { + if ( color = /^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - object.animations = []; + // hsl(120,50%,50%) hsla(120,50%,50%,0.5) - for ( let i = 0; i < this.animations.length; i ++ ) { + handleAlpha( color[ 4 ] ); - const animation = this.animations[ i ]; + return this.setHSL( + parseFloat( color[ 1 ] ) / 360, + parseFloat( color[ 2 ] ) / 100, + parseFloat( color[ 3 ] ) / 100, + colorSpace + ); - object.animations.push( serialize( meta.animations, animation ) ); + } - } + break; - } + default: - if ( isRootObject ) { + console.warn( 'THREE.Color: Unknown color model ' + style ); - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); + } - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; + } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + + // hex color + + const hex = m[ 1 ]; + const size = hex.length; - } + if ( size === 3 ) { - output.object = object; + // #ff0 + return this.setRGB( + parseInt( hex.charAt( 0 ), 16 ) / 15, + parseInt( hex.charAt( 1 ), 16 ) / 15, + parseInt( hex.charAt( 2 ), 16 ) / 15, + colorSpace + ); - return output; + } else if ( size === 6 ) { - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { + // #ff0000 + return this.setHex( parseInt( hex, 16 ), colorSpace ); - const values = []; - for ( const key in cache ) { + } else { - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + console.warn( 'THREE.Color: Invalid hex color ' + style ); } - return values; + } else if ( style && style.length > 0 ) { + + return this.setColorName( style, colorSpace ); } + return this; + } - clone( recursive ) { + setColorName( style, colorSpace = SRGBColorSpace ) { - return new this.constructor().copy( this, recursive ); + // color keywords + const hex = _colorKeywords[ style.toLowerCase() ]; - } + if ( hex !== undefined ) { - copy( source, recursive = true ) { + // red + this.setHex( hex, colorSpace ); - this.name = source.name; + } else { - this.up.copy( source.up ); + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); - 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 ); + return this; - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + } - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + clone() { - this.layers.mask = source.layers.mask; - this.visible = source.visible; + return new this.constructor( this.r, this.g, this.b ); - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + } - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + copy( color ) { - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + this.r = color.r; + this.g = color.g; + this.b = color.b; - if ( recursive === true ) { + return this; - for ( let i = 0; i < source.children.length; i ++ ) { + } - const child = source.children[ i ]; - this.add( child.clone() ); + copySRGBToLinear( color ) { - } + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); - } + return this; + + } + + copyLinearToSRGB( color ) { + + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); return this; } - } + convertSRGBToLinear() { - Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; - Object3D.DefaultMatrixWorldAutoUpdate = true; + this.copySRGBToLinear( this ); - const _v0$1 = /*@__PURE__*/ new Vector3(); - const _v1$3 = /*@__PURE__*/ new Vector3(); - const _v2$2 = /*@__PURE__*/ new Vector3(); - const _v3$1 = /*@__PURE__*/ new Vector3(); + return this; - const _vab = /*@__PURE__*/ new Vector3(); - const _vac = /*@__PURE__*/ new Vector3(); - const _vbc = /*@__PURE__*/ new Vector3(); - const _vap = /*@__PURE__*/ new Vector3(); - const _vbp = /*@__PURE__*/ new Vector3(); - const _vcp = /*@__PURE__*/ new Vector3(); + } - class Triangle { + convertLinearToSRGB() { - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + this.copyLinearToSRGB( this ); - this.a = a; - this.b = b; - this.c = c; + return this; } - static getNormal( a, b, c, target ) { + getHex( colorSpace = SRGBColorSpace ) { - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { + return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + } - } + getHexString( colorSpace = SRGBColorSpace ) { - return target.set( 0, 0, 0 ); + return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); } - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { + getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); + // h,s,l ranges are in 0.0 - 1.0 - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - const denom = ( dot00 * dot11 - dot01 * dot01 ); + const r = _color.r, g = _color.g, b = _color.b; - // collinear or singular triangle - if ( denom === 0 ) { + const max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return target.set( - 2, - 1, - 1 ); + let hue, saturation; + const lightness = ( min + max ) / 2.0; - } + if ( min === max ) { - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + hue = 0; + saturation = 0; - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); + } else { - } + const delta = max - min; - static containsPoint( point, a, b, c ) { + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - this.getBarycoord( point, a, b, c, _v3$1 ); + switch ( max ) { - return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; - } + } - static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { + hue /= 6; - this.getBarycoord( point, p1, p2, p3, _v3$1 ); + } - target.set( 0, 0 ); - target.addScaledVector( uv1, _v3$1.x ); - target.addScaledVector( uv2, _v3$1.y ); - target.addScaledVector( uv3, _v3$1.z ); + target.h = hue; + target.s = saturation; + target.l = lightness; return target; } - static isFrontFacing( a, b, c, direction ) { + getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; + target.r = _color.r; + target.g = _color.g; + target.b = _color.b; + + return target; } - set( a, b, c ) { + getStyle( colorSpace = SRGBColorSpace ) { - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - return this; + const r = _color.r, g = _color.g, b = _color.b; - } + if ( colorSpace !== SRGBColorSpace ) { - setFromPointsAndIndices( points, i0, i1, i2 ) { + // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). + return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + } - return this; + return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; } - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { + offsetHSL( h, s, l ) { - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); + this.getHSL( _hslA ); - return this; + return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); } - clone() { + add( color ) { - return new this.constructor().copy( this ); + this.r += color.r; + this.g += color.g; + this.b += color.b; + + return this; } - copy( triangle ) { + addColors( color1, color2 ) { - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; return this; } - getArea() { + addScalar( s ) { - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); + this.r += s; + this.g += s; + this.b += s; - return _v0$1.cross( _v1$3 ).length() * 0.5; + return this; } - getMidpoint( target ) { + sub( color ) { - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); + + return this; } - getNormal( target ) { + multiply( color ) { - return Triangle.getNormal( this.a, this.b, this.c, target ); + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; } - getPlane( target ) { + multiplyScalar( s ) { - return target.setFromCoplanarPoints( this.a, this.b, this.c ); + this.r *= s; + this.g *= s; + this.b *= s; + + return this; } - getBarycoord( point, target ) { + lerp( color, alpha ) { - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; } - getUV( point, uv1, uv2, uv3, target ) { + lerpColors( color1, color2, alpha ) { + + this.r = color1.r + ( color2.r - color1.r ) * alpha; + this.g = color1.g + ( color2.g - color1.g ) * alpha; + this.b = color1.b + ( color2.b - color1.b ) * alpha; - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); + return this; } - containsPoint( point ) { + lerpHSL( color, alpha ) { - return Triangle.containsPoint( point, this.a, this.b, this.c ); + 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 ); - isFrontFacing( direction ) { + this.setHSL( h, s, l ); - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); + return this; } - intersectsBox( box ) { + setFromVector3( v ) { - return box.intersectsTriangle( this ); + this.r = v.x; + this.g = v.y; + this.b = v.z; - } + return this; - closestPointToPoint( p, target ) { + } - const a = this.a, b = this.b, c = this.c; - let v, w; + applyMatrix3( m ) { - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. + const r = this.r, g = this.g, b = this.b; + const e = m.elements; - _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 ) { + 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; - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); + return this; - } + } - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { + equals( c ) { - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - } + } - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + fromArray( array, offset = 0 ) { - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; - } + return this; - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { + } - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); + toArray( array = [], offset = 0 ) { - } + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + return array; - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); + } - } + fromBufferAttribute( attribute, index ) { - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); - _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 + return this; - } + } - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; + toJSON() { - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); + return this.getHex(); } - equals( triangle ) { + *[ Symbol.iterator ]() { - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + yield this.r; + yield this.g; + yield this.b; } } - let materialId = 0; + const _color = /*@__PURE__*/ new Color(); + + Color.NAMES = _colorKeywords; + + let _materialId = 0; class Material extends EventDispatcher { @@ -8320,7 +8940,7 @@ this.isMaterial = true; - Object.defineProperty( this, 'id', { value: materialId ++ } ); + Object.defineProperty( this, 'id', { value: _materialId ++ } ); this.uuid = generateUUID(); @@ -8333,6 +8953,7 @@ this.opacity = 1; this.transparent = false; + this.alphaHash = false; this.blendSrc = SrcAlphaFactor; this.blendDst = OneMinusSrcAlphaFactor; @@ -8340,6 +8961,8 @@ 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; @@ -8372,6 +8995,7 @@ this.alphaToCoverage = false; this.premultipliedAlpha = false; + this.forceSinglePass = false; this.visible = true; @@ -8425,7 +9049,7 @@ if ( newValue === undefined ) { - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); continue; } @@ -8434,7 +9058,7 @@ if ( currentValue === undefined ) { - console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); + console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); continue; } @@ -8472,7 +9096,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'Material', generator: 'Material.toJSON' } @@ -8537,6 +9161,15 @@ } + if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; + if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; + + if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { + + data.anisotropyMap = this.anisotropyMap.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; @@ -8617,24 +9250,33 @@ if ( this.blending !== NormalBlending ) data.blending = this.blending; if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors ) data.vertexColors = true; + if ( this.vertexColors === true ) data.vertexColors = true; if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; - - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - data.colorWrite = this.colorWrite; - - data.stencilWrite = this.stencilWrite; - data.stencilWriteMask = this.stencilWriteMask; - data.stencilFunc = this.stencilFunc; - data.stencilRef = this.stencilRef; - data.stencilFuncMask = this.stencilFuncMask; - data.stencilFail = this.stencilFail; - data.stencilZFail = this.stencilZFail; - data.stencilZPass = this.stencilZPass; + if ( this.transparent === true ) data.transparent = true; + + if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; + if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; + if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; + if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; + if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; + if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; + if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); + if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; + + if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; + if ( this.depthTest === false ) data.depthTest = this.depthTest; + if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; + if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; + + if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; + if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; + if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; + if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; + if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; + if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; + if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; + if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; // rotation (SpriteMaterial) if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; @@ -8651,15 +9293,17 @@ if ( this.dithering === true ) data.dithering = true; if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + if ( this.alphaHash === true ) data.alphaHash = true; + if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; + if ( this.forceSinglePass === true ) data.forceSinglePass = true; - if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframe === true ) data.wireframe = true; if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - if ( this.flatShading === true ) data.flatShading = this.flatShading; + if ( this.flatShading === true ) data.flatShading = true; if ( this.visible === false ) data.visible = false; @@ -8667,7 +9311,7 @@ if ( this.fog === false ) data.fog = false; - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; // TODO: Copied from Object3D.toJSON @@ -8724,6 +9368,8 @@ 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; @@ -8771,8 +9417,10 @@ 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; @@ -8879,7 +9527,7 @@ class BufferAttribute { - constructor( array, itemSize, normalized ) { + constructor( array, itemSize, normalized = false ) { if ( Array.isArray( array ) ) { @@ -8894,10 +9542,12 @@ this.array = array; this.itemSize = itemSize; this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + this.normalized = normalized; this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; + this._updateRange = { offset: 0, count: - 1 }; + this.updateRanges = []; + this.gpuType = FloatType; this.version = 0; @@ -8911,6 +9561,13 @@ } + get updateRange() { + + console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 + return this._updateRange; + + } + setUsage( value ) { this.usage = value; @@ -8919,6 +9576,18 @@ } + addUpdateRange( start, count ) { + + this.updateRanges.push( { start, count } ); + + } + + clearUpdateRanges() { + + this.updateRanges.length = 0; + + } + copy( source ) { this.name = source.name; @@ -8928,6 +9597,7 @@ this.normalized = source.normalized; this.usage = source.usage; + this.gpuType = source.gpuType; return this; @@ -9043,6 +9713,26 @@ } + getComponent( index, component ) { + + let value = this.array[ index * this.itemSize + component ]; + + if ( this.normalized ) value = denormalize( value, this.array ); + + return value; + + } + + setComponent( index, component, value ) { + + if ( this.normalized ) value = normalize( value, this.array ); + + this.array[ index * this.itemSize + component ] = value; + + return this; + + } + getX( index ) { let x = this.array[ index * this.itemSize ]; @@ -9208,38 +9898,11 @@ if ( this.name !== '' ) data.name = this.name; if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; return data; } - // @deprecated - - copyColorsArray() { - - console.error( 'THREE.BufferAttribute: copyColorsArray() was removed in r144.' ); - - } - - copyVector2sArray() { - - console.error( 'THREE.BufferAttribute: copyVector2sArray() was removed in r144.' ); - - } - - copyVector3sArray() { - - console.error( 'THREE.BufferAttribute: copyVector3sArray() was removed in r144.' ); - - } - - copyVector4sArray() { - - console.error( 'THREE.BufferAttribute: copyVector4sArray() was removed in r144.' ); - - } - } class Uint16BufferAttribute extends BufferAttribute { @@ -9273,12 +9936,12 @@ } - let _id$1 = 0; + let _id$2 = 0; const _m1 = /*@__PURE__*/ new Matrix4(); const _obj = /*@__PURE__*/ new Object3D(); const _offset = /*@__PURE__*/ new Vector3(); - const _box$1 = /*@__PURE__*/ new Box3(); + const _box$2 = /*@__PURE__*/ new Box3(); const _boxMorphTargets = /*@__PURE__*/ new Box3(); const _vector$8 = /*@__PURE__*/ new Vector3(); @@ -9290,7 +9953,7 @@ this.isBufferGeometry = true; - Object.defineProperty( this, 'id', { value: _id$1 ++ } ); + Object.defineProperty( this, 'id', { value: _id$2 ++ } ); this.uuid = generateUUID(); @@ -9585,20 +10248,20 @@ for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { const morphAttribute = morphAttributesPosition[ i ]; - _box$1.setFromBufferAttribute( morphAttribute ); + _box$2.setFromBufferAttribute( morphAttribute ); if ( this.morphTargetsRelative ) { - _vector$8.addVectors( this.boundingBox.min, _box$1.min ); + _vector$8.addVectors( this.boundingBox.min, _box$2.min ); this.boundingBox.expandByPoint( _vector$8 ); - _vector$8.addVectors( this.boundingBox.max, _box$1.max ); + _vector$8.addVectors( this.boundingBox.max, _box$2.max ); this.boundingBox.expandByPoint( _vector$8 ); } else { - this.boundingBox.expandByPoint( _box$1.min ); - this.boundingBox.expandByPoint( _box$1.max ); + this.boundingBox.expandByPoint( _box$2.min ); + this.boundingBox.expandByPoint( _box$2.max ); } @@ -9647,7 +10310,7 @@ const center = this.boundingSphere.center; - _box$1.setFromBufferAttribute( position ); + _box$2.setFromBufferAttribute( position ); // process morph attributes if present @@ -9660,16 +10323,16 @@ if ( this.morphTargetsRelative ) { - _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); + _box$2.expandByPoint( _vector$8 ); - _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); + _box$2.expandByPoint( _vector$8 ); } else { - _box$1.expandByPoint( _boxMorphTargets.min ); - _box$1.expandByPoint( _boxMorphTargets.max ); + _box$2.expandByPoint( _boxMorphTargets.min ); + _box$2.expandByPoint( _boxMorphTargets.max ); } @@ -9677,7 +10340,7 @@ } - _box$1.getCenter( center ); + _box$2.getCenter( center ); // second, try to find a boundingSphere with a radius smaller than the // boundingSphere of the boundingBox: sqrt(3) smaller in the best case @@ -9989,15 +10652,6 @@ } - // @deprecated since r144 - - merge() { - - console.error( 'THREE.BufferGeometry.merge() has been removed. Use THREE.BufferGeometryUtils.mergeBufferGeometries() instead.' ); - return this; - - } - normalizeNormals() { const normals = this.attributes.normal; @@ -10120,7 +10774,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'BufferGeometry', generator: 'BufferGeometry.toJSON' } @@ -10231,7 +10885,7 @@ clone() { - return new this.constructor().copy( this ); + return new this.constructor().copy( this ); } @@ -10336,10 +10990,6 @@ this.userData = source.userData; - // geometry generator parameters - - if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters ); - return this; } @@ -10352,26 +11002,26 @@ } - const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); - const _ray$2 = /*@__PURE__*/ new Ray(); - const _sphere$3 = /*@__PURE__*/ new Sphere(); + const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); + const _ray$3 = /*@__PURE__*/ new Ray(); + const _sphere$6 = /*@__PURE__*/ new Sphere(); + const _sphereHitAt = /*@__PURE__*/ new Vector3(); const _vA$1 = /*@__PURE__*/ new Vector3(); const _vB$1 = /*@__PURE__*/ new Vector3(); const _vC$1 = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); - const _tempB = /*@__PURE__*/ new Vector3(); - const _tempC = /*@__PURE__*/ new Vector3(); - const _morphA = /*@__PURE__*/ new Vector3(); - const _morphB = /*@__PURE__*/ new Vector3(); - const _morphC = /*@__PURE__*/ new Vector3(); const _uvA$1 = /*@__PURE__*/ new Vector2(); const _uvB$1 = /*@__PURE__*/ new Vector2(); const _uvC$1 = /*@__PURE__*/ new Vector2(); + const _normalA = /*@__PURE__*/ new Vector3(); + const _normalB = /*@__PURE__*/ new Vector3(); + const _normalC = /*@__PURE__*/ new Vector3(); + const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); @@ -10408,7 +11058,7 @@ } - this.material = source.material; + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; this.geometry = source.geometry; return this; @@ -10446,6 +11096,50 @@ } + getVertexPosition( index, target ) { + + const geometry = this.geometry; + const position = geometry.attributes.position; + const morphPosition = geometry.morphAttributes.position; + const morphTargetsRelative = geometry.morphTargetsRelative; + + target.fromBufferAttribute( position, index ); + + const morphInfluences = this.morphTargetInfluences; + + if ( morphPosition && morphInfluences ) { + + _morphA.set( 0, 0, 0 ); + + for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { + + const influence = morphInfluences[ i ]; + const morphAttribute = morphPosition[ i ]; + + if ( influence === 0 ) continue; + + _tempA.fromBufferAttribute( morphAttribute, index ); + + if ( morphTargetsRelative ) { + + _morphA.addScaledVector( _tempA, influence ); + + } else { + + _morphA.addScaledVector( _tempA.sub( target ), influence ); + + } + + } + + target.add( _morphA ); + + } + + return target; + + } + raycast( raycaster, intersects ) { const geometry = this.geometry; @@ -10454,36 +11148,56 @@ if ( material === undefined ) return; - // Checking boundingSphere distance to ray + // test with bounding sphere in world space if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _sphere$3.copy( geometry.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); + _sphere$6.copy( geometry.boundingSphere ); + _sphere$6.applyMatrix4( matrixWorld ); - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; + // check distance from ray origin to bounding sphere - // + _ray$3.copy( raycaster.ray ).recast( raycaster.near ); + + if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { + + if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; + + if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; + + } + + // convert ray to local space of mesh - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + _inverseMatrix$3.copy( matrixWorld ).invert(); + _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); - // Check boundingBox before continuing + // test with bounding box in local space if ( geometry.boundingBox !== null ) { - if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; + if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; } + // test for intersections with geometry + + this._computeIntersections( raycaster, intersects, _ray$3 ); + + } + + _computeIntersections( raycaster, intersects, rayLocalSpace ) { + let intersection; + const geometry = this.geometry; + const material = this.material; + const index = geometry.index; const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; const uv = geometry.attributes.uv; - const uv2 = geometry.attributes.uv2; + const uv1 = geometry.attributes.uv1; + const normal = geometry.attributes.normal; const groups = geometry.groups; const drawRange = geometry.drawRange; @@ -10507,7 +11221,7 @@ const b = index.getX( j + 1 ); const c = index.getX( j + 2 ); - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10532,7 +11246,7 @@ const b = index.getX( i + 1 ); const c = index.getX( i + 2 ); - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10565,7 +11279,7 @@ const b = j + 1; const c = j + 2; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10590,7 +11304,7 @@ const b = i + 1; const c = i + 2; - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10619,81 +11333,32 @@ } else { - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); - - } - - if ( intersect === null ) return null; - - _intersectionPointWorld.copy( point ); - _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - - const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - - if ( distance < raycaster.near || distance > raycaster.far ) return null; - - return { - distance: distance, - point: _intersectionPointWorld.clone(), - object: object - }; - - } - - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - - _vA$1.fromBufferAttribute( position, a ); - _vB$1.fromBufferAttribute( position, b ); - _vC$1.fromBufferAttribute( position, c ); - - const morphInfluences = object.morphTargetInfluences; - - if ( morphPosition && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); - - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, a ); - _tempB.fromBufferAttribute( morphAttribute, b ); - _tempC.fromBufferAttribute( morphAttribute, c ); - - if ( morphTargetsRelative ) { - - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); + intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); - } else { + } - _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); + if ( intersect === null ) return null; - } + _intersectionPointWorld.copy( point ); + _intersectionPointWorld.applyMatrix4( object.matrixWorld ); - } + const distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld ); - _vA$1.add( _morphA ); - _vB$1.add( _morphB ); - _vC$1.add( _morphC ); + if ( distance < raycaster.near || distance > raycaster.far ) return null; - } + return { + distance: distance, + point: _intersectionPointWorld.clone(), + object: object + }; - if ( object.isSkinnedMesh ) { + } - object.boneTransform( a, _vA$1 ); - object.boneTransform( b, _vB$1 ); - object.boneTransform( c, _vC$1 ); + function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { - } + object.getVertexPosition( a, _vA$1 ); + object.getVertexPosition( b, _vB$1 ); + object.getVertexPosition( c, _vC$1 ); const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); @@ -10705,17 +11370,34 @@ _uvB$1.fromBufferAttribute( uv, b ); _uvC$1.fromBufferAttribute( uv, c ); - intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + + } + + if ( uv1 ) { + + _uvA$1.fromBufferAttribute( uv1, a ); + _uvB$1.fromBufferAttribute( uv1, b ); + _uvC$1.fromBufferAttribute( uv1, c ); + + intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv2 = intersection.uv1; // @deprecated, r152 } - if ( uv2 ) { + if ( normal ) { + + _normalA.fromBufferAttribute( normal, a ); + _normalB.fromBufferAttribute( normal, b ); + _normalC.fromBufferAttribute( normal, c ); + + intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); - _uvA$1.fromBufferAttribute( uv2, a ); - _uvB$1.fromBufferAttribute( uv2, b ); - _uvC$1.fromBufferAttribute( uv2, c ); + if ( intersection.normal.dot( ray.direction ) > 0 ) { - intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.normal.multiplyScalar( - 1 ); + + } } @@ -10894,6 +11576,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); @@ -10923,7 +11615,16 @@ property.isVector2 || property.isVector3 || property.isVector4 || property.isTexture || property.isQuaternion ) ) { - dst[ u ][ p ] = property.clone(); + if ( property.isRenderTargetTexture ) { + + console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); + dst[ u ][ p ] = null; + + } else { + + dst[ u ][ p ] = property.clone(); + + } } else if ( Array.isArray( property ) ) { @@ -10982,11 +11683,11 @@ if ( renderer.getRenderTarget() === null ) { // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 - return renderer.outputEncoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; + return renderer.outputColorSpace; } - return LinearSRGBColorSpace; + return ColorManagement.workingColorSpace; } @@ -11024,11 +11725,14 @@ this.lights = false; // set to use scene lights this.clipping = false; // set to use user-defined clipping planes + this.forceSinglePass = true; + this.extensions = { derivatives: false, // set to use derivatives fragDepth: false, // set to use fragment depth values drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD + shaderTextureLOD: false, // set to use shader texture LOD + clipCullDistance: false // set to use vertex shader clipping }; // When rendered geometry doesn't include these attributes but the material does, @@ -11036,7 +11740,7 @@ this.defaultAttributeValues = { 'color': [ 1, 1, 1 ], 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] + 'uv1': [ 0, 0 ] }; this.index0AttributeName = undefined; @@ -11157,6 +11861,9 @@ data.vertexShader = this.vertexShader; data.fragmentShader = this.fragmentShader; + data.lights = this.lights; + data.clipping = this.clipping; + const extensions = {}; for ( const key in this.extensions ) { @@ -11188,6 +11895,8 @@ this.projectionMatrix = new Matrix4(); this.projectionMatrixInverse = new Matrix4(); + this.coordinateSystem = WebGLCoordinateSystem; + } copy( source, recursive ) { @@ -11199,17 +11908,15 @@ this.projectionMatrix.copy( source.projectionMatrix ); this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + this.coordinateSystem = source.coordinateSystem; + return this; } getWorldDirection( target ) { - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); + return super.getWorldDirection( target ).negate(); } @@ -11436,7 +12143,7 @@ const skew = this.filmOffset; if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -11478,88 +12185,154 @@ this.type = 'CubeCamera'; this.renderTarget = renderTarget; + this.coordinateSystem = null; + this.activeMipmapLevel = 0; const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); cameraPX.layers = this.layers; - cameraPX.up.set( 0, 1, 0 ); - cameraPX.lookAt( 1, 0, 0 ); this.add( cameraPX ); const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); cameraNX.layers = this.layers; - cameraNX.up.set( 0, 1, 0 ); - cameraNX.lookAt( - 1, 0, 0 ); this.add( cameraNX ); const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); cameraPY.layers = this.layers; - cameraPY.up.set( 0, 0, - 1 ); - cameraPY.lookAt( 0, 1, 0 ); this.add( cameraPY ); const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); cameraNY.layers = this.layers; - cameraNY.up.set( 0, 0, 1 ); - cameraNY.lookAt( 0, - 1, 0 ); this.add( cameraNY ); const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); cameraPZ.layers = this.layers; - cameraPZ.up.set( 0, 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); this.add( cameraPZ ); const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); cameraNZ.layers = this.layers; - cameraNZ.up.set( 0, 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); this.add( cameraNZ ); } + updateCoordinateSystem() { + + const coordinateSystem = this.coordinateSystem; + + const cameras = this.children.concat(); + + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; + + for ( const camera of cameras ) this.remove( camera ); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + 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 if ( coordinateSystem === WebGPUCoordinateSystem ) { + + 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 { + + throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); + + } + + for ( const camera of cameras ) { + + this.add( camera ); + + camera.updateMatrixWorld(); + + } + + } + update( renderer, scene ) { if ( this.parent === null ) this.updateMatrixWorld(); - const renderTarget = this.renderTarget; + const { renderTarget, activeMipmapLevel } = this; + + if ( this.coordinateSystem !== renderer.coordinateSystem ) { + + this.coordinateSystem = renderer.coordinateSystem; + + this.updateCoordinateSystem(); + + } const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; const currentRenderTarget = renderer.getRenderTarget(); + const currentActiveCubeFace = renderer.getActiveCubeFace(); + const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); - const currentToneMapping = renderer.toneMapping; const currentXrEnabled = renderer.xr.enabled; - renderer.toneMapping = NoToneMapping; renderer.xr.enabled = false; const generateMipmaps = renderTarget.texture.generateMipmaps; renderTarget.texture.generateMipmaps = false; - renderer.setRenderTarget( renderTarget, 0 ); + renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); renderer.render( scene, cameraPX ); - renderer.setRenderTarget( renderTarget, 1 ); + renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); renderer.render( scene, cameraNX ); - renderer.setRenderTarget( renderTarget, 2 ); + renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); renderer.render( scene, cameraPY ); - renderer.setRenderTarget( renderTarget, 3 ); + renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); renderer.render( scene, cameraNY ); - renderer.setRenderTarget( renderTarget, 4 ); + renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); renderer.render( scene, cameraPZ ); + // mipmaps are generated during the last call of render() + // at this point, all sides of the cube render target are defined + renderTarget.texture.generateMipmaps = generateMipmaps; - renderer.setRenderTarget( renderTarget, 5 ); + renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); renderer.render( scene, cameraNZ ); - renderer.setRenderTarget( currentRenderTarget ); + renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); - renderer.toneMapping = currentToneMapping; renderer.xr.enabled = currentXrEnabled; renderTarget.texture.needsPMREMUpdate = true; @@ -11570,12 +12343,12 @@ class CubeTexture extends Texture { - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { images = images !== undefined ? images : []; mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); this.isCubeTexture = true; @@ -11608,7 +12381,15 @@ const image = { width: size, height: size, depth: 1 }; const images = [ image, image, image, image, image, image ]; - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + if ( options.encoding !== undefined ) { + + // @deprecated, r152 + warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; + + } + + this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, @@ -11628,7 +12409,7 @@ fromEquirectangularTexture( renderer, texture ) { this.texture.type = texture.type; - this.texture.encoding = texture.encoding; + this.texture.colorSpace = texture.colorSpace; this.texture.generateMipmaps = texture.generateMipmaps; this.texture.minFilter = texture.minFilter; @@ -11833,7 +12614,7 @@ projectPoint( point, target ) { - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); + return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); } @@ -11865,7 +12646,7 @@ } - return target.copy( direction ).multiplyScalar( t ).add( line.start ); + return target.copy( line.start ).addScaledVector( direction, t ); } @@ -11934,7 +12715,7 @@ } - const _sphere$2 = /*@__PURE__*/ new Sphere(); + const _sphere$5 = /*@__PURE__*/ new Sphere(); const _vector$7 = /*@__PURE__*/ new Vector3(); class Frustum { @@ -11974,7 +12755,7 @@ } - setFromProjectionMatrix( m ) { + setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { const planes = this.planes; const me = m.elements; @@ -11988,7 +12769,20 @@ planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); + + } else { + + throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); + + } return this; @@ -11996,23 +12790,33 @@ intersectsObject( object ) { - const geometry = object.geometry; + if ( object.boundingSphere !== undefined ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + + _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); - _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); + } else { + + const geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - return this.intersectsSphere( _sphere$2 ); + } + + return this.intersectsSphere( _sphere$5 ); } intersectsSprite( sprite ) { - _sphere$2.center.set( 0, 0, 0 ); - _sphere$2.radius = 0.7071067811865476; - _sphere$2.applyMatrix4( sprite.matrixWorld ); + _sphere$5.center.set( 0, 0, 0 ); + _sphere$5.radius = 0.7071067811865476; + _sphere$5.applyMatrix4( sprite.matrixWorld ); - return this.intersectsSphere( _sphere$2 ); + return this.intersectsSphere( _sphere$5 ); } @@ -12152,6 +12956,7 @@ const array = attribute.array; const usage = attribute.usage; + const size = array.byteLength; const buffer = gl.createBuffer(); @@ -12164,7 +12969,7 @@ if ( array instanceof Float32Array ) { - type = 5126; + type = gl.FLOAT; } else if ( array instanceof Uint16Array ) { @@ -12172,7 +12977,7 @@ if ( isWebGL2 ) { - type = 5131; + type = gl.HALF_FLOAT; } else { @@ -12182,33 +12987,33 @@ } else { - type = 5123; + type = gl.UNSIGNED_SHORT; } } else if ( array instanceof Int16Array ) { - type = 5122; + type = gl.SHORT; } else if ( array instanceof Uint32Array ) { - type = 5125; + type = gl.UNSIGNED_INT; } else if ( array instanceof Int32Array ) { - type = 5124; + type = gl.INT; } else if ( array instanceof Int8Array ) { - type = 5120; + type = gl.BYTE; } else if ( array instanceof Uint8Array ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else if ( array instanceof Uint8ClampedArray ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else { @@ -12220,7 +13025,8 @@ buffer: buffer, type: type, bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version + version: attribute.version, + size: size }; } @@ -12228,17 +13034,43 @@ function updateBuffer( buffer, attribute, bufferType ) { const array = attribute.array; - const updateRange = attribute.updateRange; + const updateRange = attribute._updateRange; // deprecated + const updateRanges = attribute.updateRanges; gl.bindBuffer( bufferType, buffer ); - if ( updateRange.count === - 1 ) { + if ( updateRange.count === - 1 && updateRanges.length === 0 ) { // Not using update ranges - gl.bufferSubData( bufferType, 0, array ); - } else { + } + + if ( updateRanges.length !== 0 ) { + + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + + const range = updateRanges[ i ]; + if ( isWebGL2 ) { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } else { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array.subarray( range.start, range.start + range.count ) ); + + } + + } + + attribute.clearUpdateRanges(); + + } + + // deprecated + if ( updateRange.count !== - 1 ) { if ( isWebGL2 ) { @@ -12317,6 +13149,12 @@ } else if ( data.version < attribute.version ) { + if ( data.size !== attribute.array.byteLength ) { + + throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); + + } + updateBuffer( data.buffer, attribute, bufferType ); data.version = attribute.version; @@ -12411,6 +13249,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); @@ -12419,7 +13267,11 @@ } - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; + var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; + + var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; + + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; @@ -12427,19 +13279,23 @@ var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; + var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - var begin_vertex = "vec3 transformed = vec3( position );"; + var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; + + var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; + + var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\n#ifdef USE_IRIDESCENCE\n\tvec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif"; + var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; - var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\t return vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat R21 = R12;\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; + var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos.xyz );\n\t\tvec3 vSigmaY = dFdy( surf_pos.xyz );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; + var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; @@ -12457,23 +13313,23 @@ var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; + var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_v0 0.339\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_v1 0.276\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_v4 0.046\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_v5 0.016\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_v6 0.0038\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; + var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; + var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; + var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; + var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - var encodings_pars_fragment = "vec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}"; + var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; @@ -12495,35 +13351,35 @@ var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; + var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; - var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; + var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; + var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; + var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vUv ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif"; + var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec3 sheenSpecular = vec3( 0.0 );\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX_Iridescence( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometry.viewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; + var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; + var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; + var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; @@ -12533,15 +13389,15 @@ var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; + var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; + var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; + var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; + var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; @@ -12553,9 +13409,9 @@ var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; + var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; - var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; + var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; @@ -12563,149 +13419,147 @@ var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; + var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; - var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; + var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; - var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; + var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; - var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; + var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; + var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; + var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; + var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; + var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; + var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; + var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - var shadowmap_vertex = "#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; + var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tuniform int boneTextureSize;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tfloat j = i * 4.0;\n\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\ty = dy * ( y + 0.5 );\n\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\treturn bone;\n\t}\n#endif"; + var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - - var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmission.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n#endif"; - - var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef texture2DLodEXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; + var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; + var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; - var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; + var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; - var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; + var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; + var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$g = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; + const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; + const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; + const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; + const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; + const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; + const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; + const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; + const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; + const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; + const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; + const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$2 = "#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$2 = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; + const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; 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, @@ -12726,8 +13580,8 @@ displacementmap_vertex: displacementmap_vertex, emissivemap_fragment: emissivemap_fragment, emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_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, @@ -12777,7 +13631,7 @@ clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, clearcoat_pars_fragment: clearcoat_pars_fragment, iridescence_pars_fragment: iridescence_pars_fragment, - output_fragment: output_fragment, + opaque_fragment: opaque_fragment, packing: packing, premultiplied_alpha_fragment: premultiplied_alpha_fragment, project_vertex: project_vertex, @@ -12802,9 +13656,6 @@ uv_pars_fragment: uv_pars_fragment, uv_pars_vertex: uv_pars_vertex, uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, worldpos_vertex: worldpos_vertex, background_vert: vertex$h, @@ -12855,10 +13706,11 @@ opacity: { value: 1.0 }, map: { value: null }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - uv2Transform: { value: /*@__PURE__*/ new Matrix3() }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } }, @@ -12866,6 +13718,7 @@ specularmap: { specularMap: { value: null }, + specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -12882,26 +13735,23 @@ aomap: { aoMap: { value: null }, - aoMapIntensity: { value: 1 } + aoMapIntensity: { value: 1 }, + aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, lightmap: { lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, - - emissivemap: { - - emissiveMap: { value: null } + lightMapIntensity: { value: 1 }, + lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, bumpmap: { bumpMap: { value: null }, + bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, bumpScale: { value: 1 } }, @@ -12909,6 +13759,7 @@ normalmap: { normalMap: { value: null }, + normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } }, @@ -12916,20 +13767,30 @@ displacementmap: { displacementMap: { value: null }, + displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, displacementScale: { value: 1 }, displacementBias: { value: 0 } }, - roughnessmap: { + emissivemap: { - roughnessMap: { value: null } + emissiveMap: { value: null }, + emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, metalnessmap: { - metalnessMap: { value: null } + metalnessMap: { value: null }, + metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } + + }, + + roughnessmap: { + + roughnessMap: { value: null }, + roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -13036,6 +13897,7 @@ scale: { value: 1.0 }, map: { value: null }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaTest: { value: 0 }, uvTransform: { value: /*@__PURE__*/ new Matrix3() } @@ -13048,9 +13910,10 @@ center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, rotation: { value: 0.0 }, map: { value: null }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } } @@ -13356,33 +14219,47 @@ { clearcoat: { value: 0 }, clearcoatMap: { value: null }, + clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalMap: { value: null }, + clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, clearcoatRoughness: { value: 0 }, clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatNormalMap: { value: null }, + clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescence: { value: 0 }, iridescenceMap: { value: null }, + iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescenceIOR: { value: 1.3 }, iridescenceThicknessMinimum: { value: 100 }, iridescenceThicknessMaximum: { value: 400 }, iridescenceThicknessMap: { value: null }, + iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheen: { value: 0 }, sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, sheenColorMap: { value: null }, + sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheenRoughness: { value: 1 }, sheenRoughnessMap: { value: null }, + sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmission: { value: 0 }, transmissionMap: { value: null }, + transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, transmissionSamplerMap: { value: null }, thickness: { value: 0 }, thicknessMap: { value: null }, + thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, attenuationDistance: { value: 0 }, attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, specularColorMap: { value: null }, + specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + specularIntensity: { value: 1 }, + specularIntensityMap: { value: null }, + specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, + anisotropyMap: { value: null }, + anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, } ] ), @@ -13417,26 +14294,26 @@ } - // Ignore background in AR - // TODO: Reconsider this. + if ( background === null ) { - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); + setClear( clearColor, clearAlpha ); - if ( session && session.environmentBlendMode === 'additive' ) { + } else if ( background && background.isColor ) { - background = null; + setClear( background, 1 ); + forceClear = true; } - if ( background === null ) { + const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); - setClear( clearColor, clearAlpha ); + if ( environmentBlendMode === 'additive' ) { - } else if ( background && background.isColor ) { + state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); - setClear( background, 1 ); - forceClear = true; + } else if ( environmentBlendMode === 'alpha-blend' ) { + + state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); } @@ -13492,6 +14369,7 @@ 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.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( currentBackground !== background || currentBackgroundVersion !== background.version || @@ -13547,6 +14425,7 @@ planeMesh.material.uniforms.t2D.value = background; planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; + planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( background.matrixAutoUpdate === true ) { @@ -13618,7 +14497,7 @@ function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - const maxVertexAttributes = gl.getParameter( 34921 ); + const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); const vaoAvailable = capabilities.isWebGL2 || extension !== null; @@ -13668,7 +14547,7 @@ if ( index !== null ) { - attributes.update( index, 34963 ); + attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); } @@ -13680,7 +14559,7 @@ if ( index !== null ) { - gl.bindBuffer( 34963, attributes.get( index ).buffer ); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); } @@ -13933,9 +14812,9 @@ } - function vertexAttribPointer( index, size, type, normalized, stride, offset ) { + function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { - if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { + if ( integer === true ) { gl.vertexAttribIPointer( index, size, type, stride, offset ); @@ -13993,6 +14872,10 @@ const type = attribute.type; const bytesPerElement = attribute.bytesPerElement; + // check for integer attributes (WebGL 2 only) + + const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); + if ( geometryAttribute.isInterleavedBufferAttribute ) { const data = geometryAttribute.data; @@ -14023,7 +14906,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14033,7 +14916,8 @@ type, normalized, stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement + ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, + integer ); } @@ -14064,7 +14948,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14074,7 +14958,8 @@ type, normalized, size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement + ( size / programAttribute.locationSize ) * i * bytesPerElement, + integer ); } @@ -14288,11 +15173,42 @@ } + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ], counts[ i ] ); + + } + + } else { + + extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( elementCount, mode, 1 ); + + } + + } + // this.setMode = setMode; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -14324,8 +15240,8 @@ if ( precision === 'highp' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { return 'highp'; @@ -14337,8 +15253,8 @@ if ( precision === 'mediump' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { return 'mediump'; @@ -14350,8 +15266,7 @@ } - const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || - ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); + const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; const maxPrecision = getMaxPrecision( precision ); @@ -14367,21 +15282,21 @@ const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - const maxTextures = gl.getParameter( 34930 ); - const maxVertexTextures = gl.getParameter( 35660 ); - const maxTextureSize = gl.getParameter( 3379 ); - const maxCubemapSize = gl.getParameter( 34076 ); + const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); + const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - const maxAttributes = gl.getParameter( 34921 ); - const maxVertexUniforms = gl.getParameter( 36347 ); - const maxVaryings = gl.getParameter( 36348 ); - const maxFragmentUniforms = gl.getParameter( 36349 ); + const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); + const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); + const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); const vertexTextures = maxVertexTextures > 0; const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); const floatVertexTextures = vertexTextures && floatFragmentTextures; - const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; + const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; return { @@ -14433,7 +15348,7 @@ this.numPlanes = 0; this.numIntersection = 0; - this.init = function ( planes, enableLocalClipping, camera ) { + this.init = function ( planes, enableLocalClipping ) { const enabled = planes.length !== 0 || @@ -14445,7 +15360,6 @@ localClippingEnabled = enableLocalClipping; - globalState = projectPlanes( planes, camera, 0 ); numGlobalPlanes = planes.length; return enabled; @@ -14462,7 +15376,12 @@ this.endShadows = function () { renderingShadows = false; - resetGlobalState(); + + }; + + this.setGlobalState = function ( planes, camera ) { + + globalState = projectPlanes( planes, camera, 0 ); }; @@ -14599,7 +15518,7 @@ function get( texture ) { - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { + if ( texture && texture.isTexture ) { const mapping = texture.mapping; @@ -14779,7 +15698,7 @@ } - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -14820,6 +15739,8 @@ const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); const _clearColor = /*@__PURE__*/ new Color(); let _oldTarget = null; + let _oldActiveCubeFace = 0; + let _oldActiveMipmapLevel = 0; // Golden Ratio const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; @@ -14885,6 +15806,8 @@ fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); this._setSize( 256 ); @@ -14997,7 +15920,7 @@ _cleanup( outputTarget ) { - this._renderer.setRenderTarget( _oldTarget ); + this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); outputTarget.scissorTest = false; _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); @@ -15016,6 +15939,8 @@ } _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); const cubeUVRenderTarget = renderTarget || this._allocateTargets(); this._textureToCubeUV( texture, cubeUVRenderTarget ); @@ -15037,13 +15962,13 @@ generateMipmaps: false, type: HalfFloatType, format: RGBAFormat, - encoding: LinearEncoding, + colorSpace: LinearSRGBColorSpace, depthBuffer: false }; const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width ) { + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { if ( this._pingPongRenderTarget !== null ) { @@ -15861,6 +16786,7 @@ if ( capabilities.isWebGL2 ) { getExtension( 'EXT_color_buffer_float' ); + getExtension( 'WEBGL_clip_cull_distance' ); } else { @@ -15920,6 +16846,18 @@ } + for ( const name in geometry.morphAttributes ) { + + const array = geometry.morphAttributes[ name ]; + + for ( let i = 0, l = array.length; i < l; i ++ ) { + + attributes.remove( array[ i ] ); + + } + + } + geometry.removeEventListener( 'dispose', onGeometryDispose ); delete geometries[ geometry.id ]; @@ -15969,7 +16907,7 @@ for ( const name in geometryAttributes ) { - attributes.update( geometryAttributes[ name ], 34962 ); + attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); } @@ -15983,7 +16921,7 @@ for ( let i = 0, l = array.length; i < l; i ++ ) { - attributes.update( array[ i ], 34962 ); + attributes.update( array[ i ], gl.ARRAY_BUFFER ); } @@ -16014,7 +16952,7 @@ } - } else { + } else if ( geometryPosition !== undefined ) { const array = geometryPosition.array; version = geometryPosition.version; @@ -16029,6 +16967,10 @@ } + } else { + + return; + } const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); @@ -16122,30 +17064,60 @@ if ( primcount === 0 ) return; - let extension, methodName; + let extension, methodName; + + if ( isWebGL2 ) { + + extension = gl; + methodName = 'drawElementsInstanced'; + + } else { + + extension = extensions.get( 'ANGLE_instanced_arrays' ); + methodName = 'drawElementsInstancedANGLE'; + + if ( extension === null ) { + + console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); + return; + + } + + } + + extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); + + info.update( count, mode, primcount ); + + } + + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { - if ( isWebGL2 ) { + this.render( starts[ i ] / bytesPerElement, counts[ i ] ); - extension = gl; - methodName = 'drawElementsInstanced'; + } } else { - extension = extensions.get( 'ANGLE_instanced_arrays' ); - methodName = 'drawElementsInstancedANGLE'; + extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); - if ( extension === null ) { + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { - console.error( 'THREE.WebGLIndexedBufferRenderer: using THREE.InstancedBufferGeometry but hardware does not support extension ANGLE_instanced_arrays.' ); - return; + elementCount += counts[ i ]; } - } - - extension[ methodName ]( mode, count, type, start * bytesPerElement, primcount ); + info.update( elementCount, mode, 1 ); - info.update( count, mode, primcount ); + } } @@ -16155,6 +17127,7 @@ this.setIndex = setIndex; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -16179,23 +17152,23 @@ switch ( mode ) { - case 4: + case gl.TRIANGLES: render.triangles += instanceCount * ( count / 3 ); break; - case 1: + case gl.LINES: render.lines += instanceCount * ( count / 2 ); break; - case 3: + case gl.LINE_STRIP: render.lines += instanceCount * ( count - 1 ); break; - case 2: + case gl.LINE_LOOP: render.lines += instanceCount * count; break; - case 0: + case gl.POINTS: render.points += instanceCount * count; break; @@ -16209,7 +17182,6 @@ function reset() { - render.frame ++; render.calls = 0; render.triangles = 0; render.points = 0; @@ -16255,7 +17227,7 @@ } - function update( object, geometry, material, program ) { + function update( object, geometry, program ) { const objectInfluences = object.morphTargetInfluences; @@ -16550,11 +17522,31 @@ } - attributes.update( object.instanceMatrix, 34962 ); + if ( updateMap.get( object ) !== frame ) { + + attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); + + if ( object.instanceColor !== null ) { + + attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); + + } + + updateMap.set( object, frame ); + + } + + } + + if ( object.isSkinnedMesh ) { + + const skeleton = object.skeleton; + + if ( updateMap.get( skeleton ) !== frame ) { - if ( object.instanceColor !== null ) { + skeleton.update(); - attributes.update( object.instanceColor, 34962 ); + updateMap.set( skeleton, frame ); } @@ -16591,6 +17583,60 @@ } + class DepthTexture extends Texture { + + constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + + format = format !== undefined ? format : DepthFormat; + + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + + } + + if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isDepthTexture = true; + + this.image = { width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; + + this.compareFunction = null; + + } + + + copy( source ) { + + super.copy( source ); + + this.compareFunction = source.compareFunction; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; + + return data; + + } + + } + /** * Uniforms of a program. * Those form a tree structure with a special top-level container for the root, @@ -16634,7 +17680,12 @@ * */ + const emptyTexture = /*@__PURE__*/ new Texture(); + + const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); + emptyShadowTexture.compareFunction = LessEqualCompare; + const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); @@ -17151,7 +18202,9 @@ } - textures.setTexture2D( v || emptyTexture, unit ); + const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture; + + textures.setTexture2D( v || emptyTexture2D, unit ); } @@ -17535,6 +18588,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.setValue = getSingularSetter( activeInfo.type ); // this.path = activeInfo.name; // DEBUG @@ -17550,6 +18604,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.size = activeInfo.size; this.setValue = getPureArraySetter( activeInfo.type ); @@ -17667,7 +18722,7 @@ this.seq = []; this.map = {}; - const n = gl.getProgramParameter( program, 35718 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); for ( let i = 0; i < n; ++ i ) { @@ -17742,6 +18797,9 @@ } + // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ + const COMPLETION_STATUS_KHR = 0x91B1; + let programIdCount = 0; function handleSource( string, errorLine ) { @@ -17763,17 +18821,40 @@ } - function getEncodingComponents( encoding ) { + function getEncodingComponents( colorSpace ) { + + const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); + const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); + + let gamutMapping; + + if ( workingPrimaries === encodingPrimaries ) { + + gamutMapping = ''; + + } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { + + gamutMapping = 'LinearDisplayP3ToLinearSRGB'; + + } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { + + gamutMapping = 'LinearSRGBToLinearDisplayP3'; + + } + + switch ( colorSpace ) { + + case LinearSRGBColorSpace: + case LinearDisplayP3ColorSpace: + return [ gamutMapping, 'LinearTransferOETF' ]; - switch ( encoding ) { + case SRGBColorSpace: + case DisplayP3ColorSpace: + return [ gamutMapping, 'sRGBTransferOETF' ]; - case LinearEncoding: - return [ 'Linear', '( value )' ]; - case sRGBEncoding: - return [ 'sRGB', '( value )' ]; default: - console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); - return [ 'Linear', '( value )' ]; + console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); + return [ gamutMapping, 'LinearTransferOETF' ]; } @@ -17781,7 +18862,7 @@ function getShaderErrors( gl, shader, type ) { - const status = gl.getShaderParameter( shader, 35713 ); + const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); const errors = gl.getShaderInfoLog( shader ).trim(); if ( status && errors === '' ) return ''; @@ -17803,10 +18884,10 @@ } - function getTexelEncodingFunction( functionName, encoding ) { + function getTexelEncodingFunction( functionName, colorSpace ) { - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + const components = getEncodingComponents( colorSpace ); + return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; } @@ -17832,6 +18913,10 @@ toneMappingName = 'ACESFilmic'; break; + case AgXToneMapping: + toneMappingName = 'AgX'; + break; + case CustomToneMapping: toneMappingName = 'Custom'; break; @@ -17849,7 +18934,7 @@ function generateExtensions( parameters ) { const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' @@ -17859,6 +18944,16 @@ } + function generateVertexExtensions( parameters ) { + + const chunks = [ + parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '' + ]; + + return chunks.filter( filterEmptyLine ).join( '\n' ); + + } + function generateDefines( defines ) { const chunks = []; @@ -17881,7 +18976,7 @@ const attributes = {}; - const n = gl.getProgramParameter( program, 35721 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); for ( let i = 0; i < n; i ++ ) { @@ -17889,9 +18984,9 @@ const name = info.name; let locationSize = 1; - if ( info.type === 35674 ) locationSize = 2; - if ( info.type === 35675 ) locationSize = 3; - if ( info.type === 35676 ) locationSize = 4; + if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; + if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; + if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); @@ -17950,13 +19045,30 @@ } + const shaderChunkMap = new Map( [ + [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 + [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 + [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 + ] ); + function includeReplacer( match, include ) { - const string = ShaderChunk[ include ]; + let string = ShaderChunk[ include ]; if ( string === undefined ) { - throw new Error( 'Can not resolve #include <' + include + '>' ); + const newInclude = shaderChunkMap.get( include ); + + if ( newInclude !== undefined ) { + + string = ShaderChunk[ newInclude ]; + console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); + + } else { + + throw new Error( 'Can not resolve #include <' + include + '>' ); + + } } @@ -18146,6 +19258,8 @@ const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); + const customVertexExtensions = generateVertexExtensions( parameters ); + const customDefines = generateDefines( defines ); const program = gl.createProgram(); @@ -18157,6 +19271,9 @@ prefixVertex = [ + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18170,6 +19287,10 @@ prefixFragment = [ customExtensions, + + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18186,28 +19307,33 @@ 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.instancing ? '#define USE_INSTANCING' : '', parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapModeDefine : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', @@ -18216,28 +19342,65 @@ parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', + + // + + parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', + parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', + parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', + parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', + parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', + parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', + parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', + parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', + + parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', + parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', + + parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', + + parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', + parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', + parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', + + parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', + parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', + + parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', + parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', + + parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', + parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', + parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', + parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', + + // + + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', @@ -18257,6 +19420,10 @@ parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18284,6 +19451,24 @@ 'attribute vec3 normal;', 'attribute vec2 uv;', + '#ifdef USE_UV1', + + ' attribute vec2 uv1;', + + '#endif', + + '#ifdef USE_UV2', + + ' attribute vec2 uv2;', + + '#endif', + + '#ifdef USE_UV3', + + ' attribute vec2 uv3;', + + '#endif', + '#ifdef USE_TANGENT', ' attribute vec4 tangent;', @@ -18342,12 +19527,13 @@ generatePrecision( parameters ), + '#define SHADER_TYPE ' + parameters.shaderType, '#define SHADER_NAME ' + parameters.shaderName, customDefines, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.matcap ? '#define USE_MATCAP' : '', @@ -18360,11 +19546,14 @@ envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoat ? '#define USE_CLEARCOAT' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', @@ -18376,29 +19565,32 @@ parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.alphaTest ? '#define USE_ALPHATEST' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', @@ -18412,7 +19604,11 @@ parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + + parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18428,8 +19624,8 @@ parameters.dithering ? '#define DITHERING' : '', parameters.opaque ? '#define OPAQUE' : '', - ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), + ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below + getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', @@ -18457,6 +19653,7 @@ versionString = '#version 300 es\n'; prefixVertex = [ + customVertexExtensions, 'precision mediump sampler2DArray;', '#define attribute in', '#define varying out', @@ -18464,6 +19661,7 @@ ].join( '\n' ) + '\n' + prefixVertex; prefixFragment = [ + 'precision mediump sampler2DArray;', '#define varying in', ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', @@ -18487,8 +19685,8 @@ // console.log( '*VERTEX*', vertexGlsl ); // console.log( '*FRAGMENT*', fragmentGlsl ); - const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); + const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); + const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); @@ -18508,77 +19706,94 @@ gl.linkProgram( program ); - // check for link errors - if ( renderer.debug.checkShaderErrors ) { + function onFirstUse( self ) { - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); + // check for link errors + if ( renderer.debug.checkShaderErrors ) { - let runnable = true; - let haveDiagnostics = true; + const programLog = gl.getProgramInfoLog( program ).trim(); + const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); + const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - if ( gl.getProgramParameter( program, 35714 ) === false ) { + let runnable = true; + let haveDiagnostics = true; - runnable = false; + if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); + runnable = false; - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); + if ( typeof renderer.debug.onShaderError === 'function' ) { + + renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); - } else if ( programLog !== '' ) { + } else { - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); + // default error reporting - } else if ( vertexLog === '' || fragmentLog === '' ) { + const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); + const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - haveDiagnostics = false; + console.error( + 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + + 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + + 'Program Info Log: ' + programLog + '\n' + + vertexErrors + '\n' + + fragmentErrors + ); - } + } - if ( haveDiagnostics ) { + } else if ( programLog !== '' ) { - this.diagnostics = { + console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - runnable: runnable, + } else if ( vertexLog === '' || fragmentLog === '' ) { - programLog: programLog, + haveDiagnostics = false; - vertexShader: { + } - log: vertexLog, - prefix: prefixVertex + if ( haveDiagnostics ) { - }, + self.diagnostics = { - fragmentShader: { + runnable: runnable, - log: fragmentLog, - prefix: prefixFragment + programLog: programLog, - } + vertexShader: { - }; + log: vertexLog, + prefix: prefixVertex + + }, + + fragmentShader: { + + log: fragmentLog, + prefix: prefixFragment + + } + + }; + + } } - } + // Clean up + + // Crashes in iOS9 and iOS10. #18402 + // gl.detachShader( program, glVertexShader ); + // gl.detachShader( program, glFragmentShader ); - // Clean up + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); + cachedUniforms = new WebGLUniforms( gl, program ); + cachedAttributes = fetchAttributeLocations( gl, program ); - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); + } // set up caching for uniform locations @@ -18588,7 +19803,8 @@ if ( cachedUniforms === undefined ) { - cachedUniforms = new WebGLUniforms( gl, program ); + // Populates cachedUniforms and cachedAttributes + onFirstUse( this ); } @@ -18604,7 +19820,8 @@ if ( cachedAttributes === undefined ) { - cachedAttributes = fetchAttributeLocations( gl, program ); + // Populates cachedAttributes and cachedUniforms + onFirstUse( this ); } @@ -18612,6 +19829,23 @@ }; + // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, + // flag the program as ready immediately. It may cause a stall when it's first used. + + let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); + + this.isReady = function () { + + if ( programReady === false ) { + + programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); + + } + + return programReady; + + }; + // free resource this.destroy = function () { @@ -18625,6 +19859,7 @@ // + this.type = parameters.shaderType; this.name = parameters.shaderName; this.id = programIdCount ++; this.cacheKey = cacheKey; @@ -18637,7 +19872,7 @@ } - let _id = 0; + let _id$1 = 0; class WebGLShaderCache { @@ -18751,7 +19986,7 @@ constructor( code ) { - this.id = _id ++; + this.id = _id$1 ++; this.code = code; this.usedTimes = 0; @@ -18766,9 +20001,10 @@ const _customShaders = new WebGLShaderCache(); const programs = []; - const isWebGL2 = capabilities.isWebGL2; + const IS_WEBGL2 = capabilities.isWebGL2; const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const vertexTextures = capabilities.vertexTextures; + const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; + let precision = capabilities.precision; const shaderIDs = { @@ -18789,6 +20025,14 @@ SpriteMaterial: 'sprite' }; + function getChannel( value ) { + + if ( value === 0 ) return 'uv'; + + return `uv${ value }`; + + } + function getParameters( material, lights, shadows, scene, object ) { const fog = scene.fog; @@ -18852,95 +20096,204 @@ const currentRenderTarget = renderer.getRenderTarget(); - const useAlphaTest = material.alphaTest > 0; - const useClearcoat = material.clearcoat > 0; - const useIridescence = material.iridescence > 0; + const IS_INSTANCEDMESH = object.isInstancedMesh === true; + const IS_BATCHEDMESH = object.isBatchedMesh === true; + + const HAS_MAP = !! material.map; + const HAS_MATCAP = !! material.matcap; + const HAS_ENVMAP = !! envMap; + const HAS_AOMAP = !! material.aoMap; + const HAS_LIGHTMAP = !! material.lightMap; + const HAS_BUMPMAP = !! material.bumpMap; + const HAS_NORMALMAP = !! material.normalMap; + const HAS_DISPLACEMENTMAP = !! material.displacementMap; + const HAS_EMISSIVEMAP = !! material.emissiveMap; + + const HAS_METALNESSMAP = !! material.metalnessMap; + const HAS_ROUGHNESSMAP = !! material.roughnessMap; + + const HAS_ANISOTROPY = material.anisotropy > 0; + const HAS_CLEARCOAT = material.clearcoat > 0; + const HAS_IRIDESCENCE = material.iridescence > 0; + const HAS_SHEEN = material.sheen > 0; + const HAS_TRANSMISSION = material.transmission > 0; + + const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; + + const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; + const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; + const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; + + const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; + const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; + + const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; + const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; + + const HAS_SPECULARMAP = !! material.specularMap; + const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; + const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; + + const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; + const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; + + const HAS_GRADIENTMAP = !! material.gradientMap; + + const HAS_ALPHAMAP = !! material.alphaMap; + + const HAS_ALPHATEST = material.alphaTest > 0; + + const HAS_ALPHAHASH = !! material.alphaHash; + + const HAS_EXTENSIONS = !! material.extensions; + + const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1; + const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2; + const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3; + + let toneMapping = NoToneMapping; + + if ( material.toneMapped ) { + + if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { + + toneMapping = renderer.toneMapping; + + } + + } const parameters = { - isWebGL2: isWebGL2, + isWebGL2: IS_WEBGL2, shaderID: shaderID, - shaderName: material.type, + shaderType: material.type, + shaderName: material.name, + + vertexShader: vertexShader, + fragmentShader: fragmentShader, + defines: material.defines, + + customVertexShaderID: customVertexShaderID, + customFragmentShaderID: customFragmentShaderID, + + isRawShaderMaterial: material.isRawShaderMaterial === true, + glslVersion: material.glslVersion, + + precision: precision, + + batching: IS_BATCHEDMESH, + instancing: IS_INSTANCEDMESH, + instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, + + supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, + outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), + + 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, + + normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, + normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, + + 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, + + 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, + + opaque: material.transparent === false && material.blending === NormalBlending, + + alphaMap: HAS_ALPHAMAP, + alphaTest: HAS_ALPHATEST, + alphaHash: HAS_ALPHAHASH, - vertexShader: vertexShader, - fragmentShader: fragmentShader, - defines: material.defines, + combine: material.combine, - customVertexShaderID: customVertexShaderID, - customFragmentShaderID: customFragmentShaderID, + // - isRawShaderMaterial: material.isRawShaderMaterial === true, - glslVersion: material.glslVersion, + mapUv: HAS_MAP && getChannel( material.map.channel ), + aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), + lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), + bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), + normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), + displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), + emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), - precision: precision, + metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), + roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), - instancing: object.isInstancedMesh === true, - instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, + anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), - supportsVertexTextures: vertexTextures, - outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ), - map: !! material.map, - matcap: !! material.matcap, - envMap: !! envMap, - envMapMode: envMap && envMap.mapping, - envMapCubeUVHeight: envMapCubeUVHeight, - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, - - decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ), - - clearcoat: useClearcoat, - clearcoatMap: useClearcoat && !! material.clearcoatMap, - clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, - clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, - - iridescence: useIridescence, - iridescenceMap: useIridescence && !! material.iridescenceMap, - iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap, - - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - specularIntensityMap: !! material.specularIntensityMap, - specularColorMap: !! material.specularColorMap, + clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), + clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), + clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), - opaque: material.transparent === false && material.blending === NormalBlending, + iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), + iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), - alphaMap: !! material.alphaMap, - alphaTest: useAlphaTest, + sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), + sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), - gradientMap: !! material.gradientMap, + specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), + specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), + specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), - sheen: material.sheen > 0, - sheenColorMap: !! material.sheenColorMap, - sheenRoughnessMap: !! material.sheenRoughnessMap, + transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), + thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), - transmission: material.transmission > 0, - transmissionMap: !! material.transmissionMap, - thicknessMap: !! material.thicknessMap, + alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), - combine: material.combine, + // - vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ), + vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), vertexColors: material.vertexColors, vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap, - uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap, + vertexUv1s: HAS_ATTRIBUTE_UV1, + vertexUv2s: HAS_ATTRIBUTE_UV2, + vertexUv3s: HAS_ATTRIBUTE_UV3, + + pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), fog: !! fog, useFog: material.fog === true, fogExp2: ( fog && fog.isFogExp2 ), - flatShading: !! material.flatShading, + flatShading: material.flatShading === true, - sizeAttenuation: material.sizeAttenuation, + sizeAttenuation: material.sizeAttenuation === true, logarithmicDepthBuffer: logarithmicDepthBuffer, skinning: object.isSkinnedMesh === true, @@ -18963,6 +20316,8 @@ numSpotLightShadows: lights.spotShadowMap.length, numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, + numLightProbes: lights.numLightProbes, + numClippingPlanes: clipping.numPlanes, numClipIntersection: clipping.numIntersection, @@ -18971,27 +20326,31 @@ shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, shadowMapType: renderer.shadowMap.type, - toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, + toneMapping: toneMapping, + useLegacyLights: renderer._useLegacyLights, + + decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), premultipliedAlpha: material.premultipliedAlpha, doubleSided: material.side === DoubleSide, flipSided: material.side === BackSide, - useDepthPacking: !! material.depthPacking, + useDepthPacking: material.depthPacking >= 0, depthPacking: material.depthPacking || 0, index0AttributeName: material.index0AttributeName, - extensionDerivatives: material.extensions && material.extensions.derivatives, - extensionFragDepth: material.extensions && material.extensions.fragDepth, - extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, - extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, + extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, + extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, + extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, + extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, + extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ), - rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), + rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), + rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), customProgramCacheKey: material.customProgramCacheKey() @@ -19031,7 +20390,7 @@ getProgramCacheKeyParameters( array, parameters ); getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputEncoding ); + array.push( renderer.outputColorSpace ); } @@ -19044,11 +20403,33 @@ function getProgramCacheKeyParameters( array, parameters ) { array.push( parameters.precision ); - array.push( parameters.outputEncoding ); + 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.vertexUvs ); array.push( parameters.fogExp2 ); array.push( parameters.sizeAttenuation ); array.push( parameters.morphTargetsCount ); @@ -19063,6 +20444,7 @@ 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 ); @@ -19083,64 +20465,38 @@ _programLayers.enable( 2 ); if ( parameters.instancingColor ) _programLayers.enable( 3 ); - if ( parameters.map ) - _programLayers.enable( 4 ); if ( parameters.matcap ) - _programLayers.enable( 5 ); + _programLayers.enable( 4 ); if ( parameters.envMap ) + _programLayers.enable( 5 ); + if ( parameters.normalMapObjectSpace ) _programLayers.enable( 6 ); - if ( parameters.lightMap ) + if ( parameters.normalMapTangentSpace ) _programLayers.enable( 7 ); - if ( parameters.aoMap ) + if ( parameters.clearcoat ) _programLayers.enable( 8 ); - if ( parameters.emissiveMap ) + if ( parameters.iridescence ) _programLayers.enable( 9 ); - if ( parameters.bumpMap ) + if ( parameters.alphaTest ) _programLayers.enable( 10 ); - if ( parameters.normalMap ) + if ( parameters.vertexColors ) _programLayers.enable( 11 ); - if ( parameters.objectSpaceNormalMap ) + if ( parameters.vertexAlphas ) _programLayers.enable( 12 ); - if ( parameters.tangentSpaceNormalMap ) + if ( parameters.vertexUv1s ) _programLayers.enable( 13 ); - if ( parameters.clearcoat ) + if ( parameters.vertexUv2s ) _programLayers.enable( 14 ); - if ( parameters.clearcoatMap ) + if ( parameters.vertexUv3s ) _programLayers.enable( 15 ); - if ( parameters.clearcoatRoughnessMap ) + if ( parameters.vertexTangents ) _programLayers.enable( 16 ); - if ( parameters.clearcoatNormalMap ) + if ( parameters.anisotropy ) _programLayers.enable( 17 ); - if ( parameters.iridescence ) + if ( parameters.alphaHash ) _programLayers.enable( 18 ); - if ( parameters.iridescenceMap ) + if ( parameters.batching ) _programLayers.enable( 19 ); - if ( parameters.iridescenceThicknessMap ) - _programLayers.enable( 20 ); - if ( parameters.displacementMap ) - _programLayers.enable( 21 ); - if ( parameters.specularMap ) - _programLayers.enable( 22 ); - if ( parameters.roughnessMap ) - _programLayers.enable( 23 ); - if ( parameters.metalnessMap ) - _programLayers.enable( 24 ); - if ( parameters.gradientMap ) - _programLayers.enable( 25 ); - if ( parameters.alphaMap ) - _programLayers.enable( 26 ); - if ( parameters.alphaTest ) - _programLayers.enable( 27 ); - if ( parameters.vertexColors ) - _programLayers.enable( 28 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 29 ); - if ( parameters.vertexUvs ) - _programLayers.enable( 30 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 31 ); - if ( parameters.uvsVertexOnly ) - _programLayers.enable( 32 ); array.push( _programLayers.mask ); _programLayers.disableAll(); @@ -19165,7 +20521,7 @@ _programLayers.enable( 8 ); if ( parameters.shadowMapEnabled ) _programLayers.enable( 9 ); - if ( parameters.physicallyCorrectLights ) + if ( parameters.useLegacyLights ) _programLayers.enable( 10 ); if ( parameters.doubleSided ) _programLayers.enable( 11 ); @@ -19175,26 +20531,16 @@ _programLayers.enable( 13 ); if ( parameters.dithering ) _programLayers.enable( 14 ); - if ( parameters.specularIntensityMap ) + if ( parameters.transmission ) _programLayers.enable( 15 ); - if ( parameters.specularColorMap ) + if ( parameters.sheen ) _programLayers.enable( 16 ); - if ( parameters.transmission ) + if ( parameters.opaque ) _programLayers.enable( 17 ); - if ( parameters.transmissionMap ) + if ( parameters.pointsUvs ) _programLayers.enable( 18 ); - if ( parameters.thicknessMap ) - _programLayers.enable( 19 ); - if ( parameters.sheen ) - _programLayers.enable( 20 ); - if ( parameters.sheenColorMap ) - _programLayers.enable( 21 ); - if ( parameters.sheenRoughnessMap ) - _programLayers.enable( 22 ); if ( parameters.decodeVideoTexture ) - _programLayers.enable( 23 ); - if ( parameters.opaque ) - _programLayers.enable( 24 ); + _programLayers.enable( 19 ); array.push( _programLayers.mask ); @@ -19741,7 +21087,9 @@ numDirectionalShadows: - 1, numPointShadows: - 1, numSpotShadows: - 1, - numSpotMaps: - 1 + numSpotMaps: - 1, + + numLightProbes: - 1 }, ambient: [ 0, 0, 0 ], @@ -19763,7 +21111,8 @@ pointShadowMap: [], pointShadowMatrix: [], hemi: [], - numSpotLightShadowsWithMaps: 0 + numSpotLightShadowsWithMaps: 0, + numLightProbes: 0 }; @@ -19773,7 +21122,7 @@ const matrix4 = new Matrix4(); const matrix42 = new Matrix4(); - function setup( lights, physicallyCorrectLights ) { + function setup( lights, useLegacyLights ) { let r = 0, g = 0, b = 0; @@ -19791,11 +21140,13 @@ let numSpotMaps = 0; let numSpotShadowsWithMaps = 0; + let numLightProbes = 0; + // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] lights.sort( shadowCastingAndTexturingLightsFirst ); // artist-friendly light intensity scaling factor - const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; for ( let i = 0, l = lights.length; i < l; i ++ ) { @@ -19821,6 +21172,8 @@ } + numLightProbes ++; + } else if ( light.isDirectionalLight ) { const uniforms = cache.get( light ); @@ -19967,8 +21320,17 @@ // WebGL 2 - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; + if ( extensions.has( 'OES_texture_float_linear' ) === true ) { + + 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; + + } } else { @@ -20008,7 +21370,8 @@ hash.numDirectionalShadows !== numDirectionalShadows || hash.numPointShadows !== numPointShadows || hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps ) { + hash.numSpotMaps !== numSpotMaps || + hash.numLightProbes !== numLightProbes ) { state.directional.length = directionalLength; state.spot.length = spotLength; @@ -20027,6 +21390,7 @@ state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; state.spotLightMap.length = numSpotMaps; state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; + state.numLightProbes = numLightProbes; hash.directionalLength = directionalLength; hash.pointLength = pointLength; @@ -20039,6 +21403,8 @@ hash.numSpotShadows = numSpotShadows; hash.numSpotMaps = numSpotMaps; + hash.numLightProbes = numLightProbes; + state.version = nextVersion ++; } @@ -20163,9 +21529,9 @@ } - function setupLights( physicallyCorrectLights ) { + function setupLights( useLegacyLights ) { - lights.setup( lightsArray, physicallyCorrectLights ); + lights.setup( lightsArray, useLegacyLights ); } @@ -20300,10 +21666,6 @@ this.type = 'MeshDistanceMaterial'; - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; - this.map = null; this.alphaMap = null; @@ -20320,10 +21682,6 @@ super.copy( source ); - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; - this.map = source.map; this.alphaMap = source.alphaMap; @@ -20358,7 +21716,7 @@ _maxTextureSize = _capabilities.maxTextureSize; - const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; const shadowMaterialVertical = new ShaderMaterial( { defines: { @@ -20397,6 +21755,7 @@ this.needsUpdate = false; this.type = PCFShadowMap; + let _previousType = this.type; this.render = function ( lights, scene, camera ) { @@ -20417,6 +21776,11 @@ _state.buffers.depth.setTest( true ); _state.setScissorTest( false ); + // check for shadow map type changes + + const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); + const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); + // render depth map for ( let i = 0, il = lights.length; i < il; i ++ ) { @@ -20461,10 +21825,16 @@ } - if ( shadow.map === null ) { + if ( shadow.map === null || toVSM === true || fromVSM === true ) { const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; + if ( shadow.map !== null ) { + + shadow.map.dispose(); + + } + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); shadow.map.texture.name = light.name + '.shadowMap'; @@ -20510,6 +21880,8 @@ } + _previousType = this.type; + scope.needsUpdate = false; _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); @@ -20556,7 +21928,7 @@ } - function getDepthMaterial( object, material, light, shadowCameraNear, shadowCameraFar, type ) { + function getDepthMaterial( object, material, light, type ) { let result = null; @@ -20570,37 +21942,38 @@ result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - } + if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || + ( material.displacementMap && material.displacementScale !== 0 ) || + ( material.alphaMap && material.alphaTest > 0 ) || + ( material.map && material.alphaTest > 0 ) ) { - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) || - ( material.map && material.alphaTest > 0 ) ) { + // in this case we need a unique material instance reflecting the + // appropriate state - // in this case we need a unique material instance reflecting the - // appropriate state + const keyA = result.uuid, keyB = material.uuid; - const keyA = result.uuid, keyB = material.uuid; + let materialsForVariant = _materialCache[ keyA ]; - let materialsForVariant = _materialCache[ keyA ]; + if ( materialsForVariant === undefined ) { - if ( materialsForVariant === undefined ) { + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + } - } + let cachedMaterial = materialsForVariant[ keyB ]; - let cachedMaterial = materialsForVariant[ keyB ]; + if ( cachedMaterial === undefined ) { - if ( cachedMaterial === undefined ) { + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; + material.addEventListener( 'dispose', onMaterialDispose ); - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + } - } + result = cachedMaterial; - result = cachedMaterial; + } } @@ -20634,9 +22007,8 @@ if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - result.referencePosition.setFromMatrixPosition( light.matrixWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + const materialProperties = _renderer.properties.get( result ); + materialProperties.light = light; } @@ -20670,20 +22042,28 @@ if ( groupMaterial && groupMaterial.visible ) { - const depthMaterial = getDepthMaterial( object, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); + } } } else if ( material.visible ) { - const depthMaterial = getDepthMaterial( object, material, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, material, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); + } } @@ -20700,6 +22080,32 @@ } + function onMaterialDispose( event ) { + + const material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + // make sure to remove the unique distance/depth materials used for shadow map rendering + + for ( const id in _materialCache ) { + + const cache = _materialCache[ id ]; + + const uuid = event.target.uuid; + + if ( uuid in cache ) { + + const shadowMaterial = cache[ uuid ]; + shadowMaterial.dispose(); + delete cache[ uuid ]; + + } + + } + + } + } function WebGLState( gl, extensions, capabilities ) { @@ -20779,11 +22185,11 @@ if ( depthTest ) { - enable( 2929 ); + enable( gl.DEPTH_TEST ); } else { - disable( 2929 ); + disable( gl.DEPTH_TEST ); } @@ -20808,47 +22214,47 @@ case NeverDepth: - gl.depthFunc( 512 ); + gl.depthFunc( gl.NEVER ); break; case AlwaysDepth: - gl.depthFunc( 519 ); + gl.depthFunc( gl.ALWAYS ); break; case LessDepth: - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); break; case LessEqualDepth: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); break; case EqualDepth: - gl.depthFunc( 514 ); + gl.depthFunc( gl.EQUAL ); break; case GreaterEqualDepth: - gl.depthFunc( 518 ); + gl.depthFunc( gl.GEQUAL ); break; case GreaterDepth: - gl.depthFunc( 516 ); + gl.depthFunc( gl.GREATER ); break; case NotEqualDepth: - gl.depthFunc( 517 ); + gl.depthFunc( gl.NOTEQUAL ); break; default: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); } @@ -20910,11 +22316,11 @@ if ( stencilTest ) { - enable( 2960 ); + enable( gl.STENCIL_TEST ); } else { - disable( 2960 ); + disable( gl.STENCIL_TEST ); } @@ -21008,7 +22414,7 @@ const stencilBuffer = new StencilBuffer(); const uboBindings = new WeakMap(); - const uboProgamMap = new WeakMap(); + const uboProgramMap = new WeakMap(); let enabledCapabilities = {}; @@ -21026,6 +22432,8 @@ let currentBlendEquationAlpha = null; let currentBlendSrcAlpha = null; let currentBlendDstAlpha = null; + let currentBlendColor = new Color( 0, 0, 0 ); + let currentBlendAlpha = 0; let currentPremultipledAlpha = false; let currentFlipSided = null; @@ -21036,11 +22444,11 @@ let currentPolygonOffsetFactor = null; let currentPolygonOffsetUnits = null; - const maxTextures = gl.getParameter( 35661 ); + const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); let lineWidthAvailable = false; let version = 0; - const glVersion = gl.getParameter( 7938 ); + const glVersion = gl.getParameter( gl.VERSION ); if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { @@ -21057,24 +22465,32 @@ let currentTextureSlot = null; let currentBoundTextures = {}; - const scissorParam = gl.getParameter( 3088 ); - const viewportParam = gl.getParameter( 2978 ); + const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); + const viewportParam = gl.getParameter( gl.VIEWPORT ); const currentScissor = new Vector4().fromArray( scissorParam ); const currentViewport = new Vector4().fromArray( viewportParam ); - function createTexture( type, target, count ) { + function createTexture( type, target, count, dimensions ) { const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. const texture = gl.createTexture(); gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); + gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); for ( let i = 0; i < count; i ++ ) { - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); + if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { + + gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } else { + + gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } } @@ -21083,8 +22499,15 @@ } const emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); + emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); + emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); + + if ( isWebGL2 ) { + + emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); + emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); + + } // init @@ -21092,12 +22515,12 @@ depthBuffer.setClear( 1 ); stencilBuffer.setClear( 0 ); - enable( 2929 ); + enable( gl.DEPTH_TEST ); depthBuffer.setFunc( LessEqualDepth ); setFlipSided( false ); setCullFace( CullFaceBack ); - enable( 2884 ); + enable( gl.CULL_FACE ); setBlending( NoBlending ); @@ -21135,17 +22558,17 @@ if ( isWebGL2 ) { - // 36009 is equivalent to 36160 + // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER - if ( target === 36009 ) { + if ( target === gl.DRAW_FRAMEBUFFER ) { - currentBoundFramebuffers[ 36160 ] = framebuffer; + currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; } - if ( target === 36160 ) { + if ( target === gl.FRAMEBUFFER ) { - currentBoundFramebuffers[ 36009 ] = framebuffer; + currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; } @@ -21180,11 +22603,11 @@ const textures = renderTarget.texture; - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { for ( let i = 0, il = textures.length; i < il; i ++ ) { - drawBuffers[ i ] = 36064 + i; + drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; } @@ -21196,9 +22619,9 @@ } else { - if ( drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - drawBuffers[ 0 ] = 36064; + drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; needsUpdate = true; @@ -21208,9 +22631,9 @@ } else { - if ( drawBuffers[ 0 ] !== 1029 ) { + if ( drawBuffers[ 0 ] !== gl.BACK ) { - drawBuffers[ 0 ] = 1029; + drawBuffers[ 0 ] = gl.BACK; needsUpdate = true; @@ -21252,15 +22675,15 @@ } const equationToGL = { - [ AddEquation ]: 32774, - [ SubtractEquation ]: 32778, - [ ReverseSubtractEquation ]: 32779 + [ AddEquation ]: gl.FUNC_ADD, + [ SubtractEquation ]: gl.FUNC_SUBTRACT, + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT }; if ( isWebGL2 ) { - equationToGL[ MinEquation ] = 32775; - equationToGL[ MaxEquation ] = 32776; + equationToGL[ MinEquation ] = gl.MIN; + equationToGL[ MaxEquation ] = gl.MAX; } else { @@ -21276,26 +22699,30 @@ } const factorToGL = { - [ ZeroFactor ]: 0, - [ OneFactor ]: 1, - [ SrcColorFactor ]: 768, - [ SrcAlphaFactor ]: 770, - [ SrcAlphaSaturateFactor ]: 776, - [ DstColorFactor ]: 774, - [ DstAlphaFactor ]: 772, - [ OneMinusSrcColorFactor ]: 769, - [ OneMinusSrcAlphaFactor ]: 771, - [ OneMinusDstColorFactor ]: 775, - [ OneMinusDstAlphaFactor ]: 773 + [ 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 }; - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { if ( blending === NoBlending ) { if ( currentBlendingEnabled === true ) { - disable( 3042 ); + disable( gl.BLEND ); currentBlendingEnabled = false; } @@ -21306,7 +22733,7 @@ if ( currentBlendingEnabled === false ) { - enable( 3042 ); + enable( gl.BLEND ); currentBlendingEnabled = true; } @@ -21317,7 +22744,7 @@ if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - gl.blendEquation( 32774 ); + gl.blendEquation( gl.FUNC_ADD ); currentBlendEquation = AddEquation; currentBlendEquationAlpha = AddEquation; @@ -21329,19 +22756,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); + gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 1, 1 ); + gl.blendFunc( gl.ONE, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); + gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); break; default: @@ -21355,19 +22782,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 770, 1 ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFunc( 0, 768 ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); break; default: @@ -21382,6 +22809,8 @@ currentBlendDst = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor.set( 0, 0, 0 ); + currentBlendAlpha = 0; currentBlending = blending; currentPremultipledAlpha = premultipliedAlpha; @@ -21418,6 +22847,15 @@ } + if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { + + gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); + + currentBlendColor.copy( blendColor ); + currentBlendAlpha = blendAlpha; + + } + currentBlending = blending; currentPremultipledAlpha = false; @@ -21426,8 +22864,8 @@ function setMaterial( material, frontFaceCW ) { material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); + ? disable( gl.CULL_FACE ) + : enable( gl.CULL_FACE ); let flipSided = ( material.side === BackSide ); if ( frontFaceCW ) flipSided = ! flipSided; @@ -21436,7 +22874,7 @@ ( material.blending === NormalBlending && material.transparent === false ) ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); depthBuffer.setFunc( material.depthFunc ); depthBuffer.setTest( material.depthTest ); @@ -21456,8 +22894,8 @@ setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); material.alphaToCoverage === true - ? enable( 32926 ) - : disable( 32926 ); + ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) + : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); } @@ -21469,11 +22907,11 @@ if ( flipSided ) { - gl.frontFace( 2304 ); + gl.frontFace( gl.CW ); } else { - gl.frontFace( 2305 ); + gl.frontFace( gl.CCW ); } @@ -21487,21 +22925,21 @@ if ( cullFace !== CullFaceNone ) { - enable( 2884 ); + enable( gl.CULL_FACE ); if ( cullFace !== currentCullFace ) { if ( cullFace === CullFaceBack ) { - gl.cullFace( 1029 ); + gl.cullFace( gl.BACK ); } else if ( cullFace === CullFaceFront ) { - gl.cullFace( 1028 ); + gl.cullFace( gl.FRONT ); } else { - gl.cullFace( 1032 ); + gl.cullFace( gl.FRONT_AND_BACK ); } @@ -21509,7 +22947,7 @@ } else { - disable( 2884 ); + disable( gl.CULL_FACE ); } @@ -21533,7 +22971,7 @@ if ( polygonOffset ) { - enable( 32823 ); + enable( gl.POLYGON_OFFSET_FILL ); if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { @@ -21546,7 +22984,7 @@ } else { - disable( 32823 ); + disable( gl.POLYGON_OFFSET_FILL ); } @@ -21556,11 +22994,11 @@ if ( scissorTest ) { - enable( 3089 ); + enable( gl.SCISSOR_TEST ); } else { - disable( 3089 ); + disable( gl.SCISSOR_TEST ); } @@ -21570,7 +23008,7 @@ function activeTexture( webglSlot ) { - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; if ( currentTextureSlot !== webglSlot ) { @@ -21587,7 +23025,7 @@ if ( currentTextureSlot === null ) { - webglSlot = 33984 + maxTextures - 1; + webglSlot = gl.TEXTURE0 + maxTextures - 1; } else { @@ -21805,13 +23243,13 @@ function updateUBOMapping( uniformsGroup, program ) { - let mapping = uboProgamMap.get( program ); + let mapping = uboProgramMap.get( program ); if ( mapping === undefined ) { mapping = new WeakMap(); - uboProgamMap.set( program, mapping ); + uboProgramMap.set( program, mapping ); } @@ -21829,16 +23267,15 @@ function uniformBlockBinding( uniformsGroup, program ) { - const mapping = uboProgamMap.get( program ); + const mapping = uboProgramMap.get( program ); const blockIndex = mapping.get( uniformsGroup ); - if ( uboBindings.get( uniformsGroup ) !== blockIndex ) { + if ( uboBindings.get( program ) !== blockIndex ) { // bind shader specific block index to global block point - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - uboBindings.set( uniformsGroup, blockIndex ); + uboBindings.set( program, blockIndex ); } @@ -21850,43 +23287,44 @@ // reset state - gl.disable( 3042 ); - gl.disable( 2884 ); - gl.disable( 2929 ); - gl.disable( 32823 ); - gl.disable( 3089 ); - gl.disable( 2960 ); - gl.disable( 32926 ); + 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( 32774 ); - gl.blendFunc( 1, 0 ); - gl.blendFuncSeparate( 1, 0, 1, 0 ); + 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.colorMask( true, true, true, true ); gl.clearColor( 0, 0, 0, 0 ); gl.depthMask( true ); - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); gl.clearDepth( 1 ); gl.stencilMask( 0xffffffff ); - gl.stencilFunc( 519, 0, 0xffffffff ); - gl.stencilOp( 7680, 7680, 7680 ); + gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); + gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); gl.clearStencil( 0 ); - gl.cullFace( 1029 ); - gl.frontFace( 2305 ); + gl.cullFace( gl.BACK ); + gl.frontFace( gl.CCW ); gl.polygonOffset( 0, 0 ); - gl.activeTexture( 33984 ); + gl.activeTexture( gl.TEXTURE0 ); - gl.bindFramebuffer( 36160, null ); + gl.bindFramebuffer( gl.FRAMEBUFFER, null ); if ( isWebGL2 === true ) { - gl.bindFramebuffer( 36009, null ); - gl.bindFramebuffer( 36008, null ); + gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); + gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); } @@ -21918,6 +23356,8 @@ currentBlendEquationAlpha = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor = new Color( 0, 0, 0 ); + currentBlendAlpha = 0; currentPremultipledAlpha = false; currentFlipSided = null; @@ -21994,10 +23434,6 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { const isWebGL2 = capabilities.isWebGL2; - const maxTextures = capabilities.maxTextures; - const maxCubemapSize = capabilities.maxCubemapSize; - const maxTextureSize = capabilities.maxTextureSize; - const maxSamples = capabilities.maxSamples; const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); @@ -22123,7 +23559,7 @@ } - function getInternalFormat( internalFormatName, glFormat, glType, encoding, forceLinearEncoding = false ) { + function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { if ( isWebGL2 === false ) return glFormat; @@ -22137,35 +23573,48 @@ let internalFormat = glFormat; - if ( glFormat === 6403 ) { + if ( glFormat === _gl.RED ) { + + if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; + + } + + if ( glFormat === _gl.RED_INTEGER ) { - if ( glType === 5126 ) internalFormat = 33326; - if ( glType === 5131 ) internalFormat = 33325; - if ( glType === 5121 ) internalFormat = 33321; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; + if ( glType === _gl.INT ) internalFormat = _gl.R32I; } - if ( glFormat === 33319 ) { + if ( glFormat === _gl.RG ) { - if ( glType === 5126 ) internalFormat = 33328; - if ( glType === 5131 ) internalFormat = 33327; - if ( glType === 5121 ) internalFormat = 33323; + if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; } - if ( glFormat === 6408 ) { + if ( glFormat === _gl.RGBA ) { - if ( glType === 5126 ) internalFormat = 34836; - if ( glType === 5131 ) internalFormat = 34842; - if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding && forceLinearEncoding === false ) ? 35907 : 32856; - if ( glType === 32819 ) internalFormat = 32854; - if ( glType === 32820 ) internalFormat = 32855; + const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); + + if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; + if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; + if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; } - if ( internalFormat === 33325 || internalFormat === 33326 || - internalFormat === 33327 || internalFormat === 33328 || - internalFormat === 34842 || internalFormat === 34836 ) { + if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || + internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || + internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { extensions.get( 'EXT_color_buffer_float' ); @@ -22207,11 +23656,11 @@ if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - return 9728; + return _gl.NEAREST; } - return 9729; + return _gl.LINEAR; } @@ -22321,14 +23770,32 @@ for ( let i = 0; i < 6; i ++ ) { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); } } else { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); @@ -22385,9 +23852,9 @@ const textureUnit = textureUnits; - if ( textureUnit >= maxTextures ) { + if ( textureUnit >= capabilities.maxTextures ) { - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); + console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); } @@ -22414,7 +23881,7 @@ array.push( texture.premultiplyAlpha ); array.push( texture.flipY ); array.push( texture.unpackAlignment ); - array.push( texture.encoding ); + array.push( texture.colorSpace ); return array.join(); @@ -22449,7 +23916,7 @@ } - state.bindTexture( 3553, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22464,7 +23931,7 @@ } - state.bindTexture( 35866, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22479,7 +23946,7 @@ } - state.bindTexture( 32879, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22494,50 +23961,61 @@ } - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } const wrappingToGL = { - [ RepeatWrapping ]: 10497, - [ ClampToEdgeWrapping ]: 33071, - [ MirroredRepeatWrapping ]: 33648 + [ RepeatWrapping ]: _gl.REPEAT, + [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, + [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT }; const filterToGL = { - [ NearestFilter ]: 9728, - [ NearestMipmapNearestFilter ]: 9984, - [ NearestMipmapLinearFilter ]: 9986, + [ 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 + }; - [ LinearFilter ]: 9729, - [ LinearMipmapNearestFilter ]: 9985, - [ LinearMipmapLinearFilter ]: 9987 + 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 }; function setTextureParameters( textureType, texture, supportsMips ) { if ( supportsMips ) { - _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); } - _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); } else { - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); } @@ -22547,8 +24025,8 @@ } - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { @@ -22558,10 +24036,19 @@ } + 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 ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + if ( texture.magFilter === NearestFilter ) return; + if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only @@ -22658,43 +24145,47 @@ function uploadTexture( textureProperties, texture, slot ) { - let textureType = 3553; + let textureType = _gl.TEXTURE_2D; - if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = 35866; - if ( texture.isData3DTexture ) textureType = 32879; + if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; + if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( textureType, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); + let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); image = verifyColorSpace( texture, image ); const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ); + glFormat = utils.convert( texture.format, texture.colorSpace ); let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); setTextureParameters( textureType, texture, supportsMips ); let mipmap; const mipmaps = texture.mipmaps; - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); + const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); const levels = getMipLevels( texture, image, supportsMips ); @@ -22702,25 +24193,25 @@ // populate depth texture with dummy data - glInternalFormat = 6402; + glInternalFormat = _gl.DEPTH_COMPONENT; if ( isWebGL2 ) { if ( texture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( texture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } else if ( texture.type === UnsignedInt248Type ) { - glInternalFormat = 35056; + glInternalFormat = _gl.DEPTH24_STENCIL8; } else { - glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D + glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D } @@ -22736,7 +24227,7 @@ // validation checks for WebGL 1 - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT @@ -22752,11 +24243,11 @@ } - if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // Depth stencil textures need the DEPTH_STENCIL internal format // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = 34041; + glInternalFormat = _gl.DEPTH_STENCIL; // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. @@ -22778,11 +24269,11 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, 1, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); } @@ -22798,7 +24289,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22808,11 +24299,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22826,15 +24317,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); } @@ -22846,7 +24337,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); } @@ -22860,11 +24351,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); + state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); } else { - state.compressedTexImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); + state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); } @@ -22878,11 +24369,11 @@ if ( useTexStorage ) { - state.texSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); } else { - state.texImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); } @@ -22894,7 +24385,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22908,11 +24399,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -22926,11 +24417,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22946,15 +24437,15 @@ if ( allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 35866, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22964,15 +24455,15 @@ if ( allocateMemory ) { - state.texStorage3D( 32879, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 32879, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22982,7 +24473,7 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } else { @@ -22990,7 +24481,7 @@ for ( let i = 0; i < levels; i ++ ) { - state.texImage2D( 3553, i, glInternalFormat, width, height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); width >>= 1; height >>= 1; @@ -23013,7 +24504,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -23023,11 +24514,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, glFormat, glType, mipmap ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); } else { - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); } @@ -23041,15 +24532,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, glFormat, glType, image ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); } else { - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); } @@ -23080,18 +24571,22 @@ const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); @@ -23102,7 +24597,7 @@ if ( ! isCompressed && ! isDataTexture ) { - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); + cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); } else { @@ -23116,15 +24611,15 @@ const image = cubeImage[ 0 ], supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ), + glFormat = utils.convert( texture.format, texture.colorSpace ), glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); let levels = getMipLevels( texture, image, supportsMips ); - setTextureParameters( 34067, texture, supportsMips ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); let mipmaps; @@ -23132,7 +24627,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 34067, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); } @@ -23150,11 +24645,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -23168,11 +24663,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -23194,7 +24689,7 @@ if ( mipmaps.length > 0 ) levels ++; - state.texStorage2D( 34067, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); } @@ -23204,11 +24699,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); } @@ -23219,11 +24714,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); } @@ -23233,11 +24728,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); } @@ -23247,11 +24742,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); } @@ -23266,7 +24761,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { // We assume images for cube map have the same size. - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23283,40 +24778,43 @@ // Render targets // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { + function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const renderTargetProperties = properties.get( renderTarget ); if ( ! renderTargetProperties.__hasExternalTextures ) { - if ( textureTarget === 32879 || textureTarget === 35866 ) { + const width = Math.max( 1, renderTarget.width >> level ); + const height = Math.max( 1, renderTarget.height >> level ); - state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); + if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { + + state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); } else { - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); } } - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - } else if ( textureTarget === 3553 || ( textureTarget >= 34069 && textureTarget <= 34074 ) ) { // see #24753 + } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23324,11 +24822,11 @@ // Setup storage for internal depth/stencil buffers and bind to correct framebuffer function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - _gl.bindRenderbuffer( 36161, renderbuffer ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - let glInternalFormat = 33189; + let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; if ( isMultisample || useMultisampledRTT( renderTarget ) ) { @@ -23338,11 +24836,11 @@ if ( depthTexture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( depthTexture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } @@ -23352,21 +24850,21 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { @@ -23374,20 +24872,20 @@ if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else { @@ -23397,22 +24895,22 @@ const texture = textures[ i ]; - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const samples = getRenderTargetSamples( renderTarget ); if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } @@ -23420,7 +24918,7 @@ } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); } @@ -23430,7 +24928,7 @@ const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { @@ -23458,11 +24956,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 36096, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23470,11 +24968,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 33306, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23506,7 +25004,7 @@ for ( let i = 0; i < 6; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); @@ -23514,7 +25012,7 @@ } else { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); @@ -23522,7 +25020,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23533,7 +25031,7 @@ if ( colorTexture !== undefined ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, 36064, 3553 ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); } @@ -23580,13 +25078,41 @@ for ( let i = 0; i < 6; i ++ ) { - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer[ i ] = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + + } } } else { - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + + } if ( isMultipleRenderTargets ) { @@ -23623,26 +25149,26 @@ renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); renderTargetProperties.__webglColorRenderbuffer = []; - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { const texture = textures[ i ]; renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, renderTarget.isXRRenderTarget === true ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); if ( renderTarget.depthBuffer ) { @@ -23651,7 +25177,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23661,18 +25187,30 @@ if ( isCube ) { - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, texture, supportsMips ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); for ( let i = 0; i < 6; i ++ ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + 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, supportsMips ) ) { - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23687,13 +25225,13 @@ const attachment = textures[ i ]; const attachmentProperties = properties.get( attachment ); - state.bindTexture( 3553, attachmentProperties.__webglTexture ); - setTextureParameters( 3553, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); + state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - generateMipmap( 3553 ); + generateMipmap( _gl.TEXTURE_2D ); } @@ -23703,13 +25241,13 @@ } else { - let glTextureType = 3553; + let glTextureType = _gl.TEXTURE_2D; if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { if ( isWebGL2 ) { - glTextureType = renderTarget.isWebGL3DRenderTarget ? 32879 : 35866; + glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; } else { @@ -23721,7 +25259,20 @@ state.bindTexture( glTextureType, textureProperties.__webglTexture ); setTextureParameters( glTextureType, texture, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); + + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); + + } + + } else { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); + + } if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { @@ -23755,7 +25306,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; + const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; const webglTexture = properties.get( texture ).__webglTexture; state.bindTexture( target, webglTexture ); @@ -23775,9 +25326,9 @@ const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; const width = renderTarget.width; const height = renderTarget.height; - let mask = 16384; + let mask = _gl.COLOR_BUFFER_BIT; const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? 33306 : 36096; + const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; const renderTargetProperties = properties.get( renderTarget ); const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); @@ -23786,22 +25337,22 @@ for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, null, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); } } - state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { - invalidationArray.push( 36064 + i ); + invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); if ( renderTarget.depthBuffer ) { @@ -23813,63 +25364,63 @@ if ( ignoreDepthValues === false ) { - if ( renderTarget.depthBuffer ) mask |= 256; - if ( renderTarget.stencilBuffer ) mask |= 1024; + if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; + if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; } if ( isMultipleRenderTargets ) { - _gl.framebufferRenderbuffer( 36008, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } if ( ignoreDepthValues === true ) { - _gl.invalidateFramebuffer( 36008, [ depthStyle ] ); - _gl.invalidateFramebuffer( 36009, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); } if ( isMultipleRenderTargets ) { const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( 36009, 36064, 3553, webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); } - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); + _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); if ( supportsInvalidateFramebuffer ) { - _gl.invalidateFramebuffer( 36008, invalidationArray ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); } } - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, null ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments if ( isMultipleRenderTargets ) { for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + 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( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, webglTexture, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); } } - state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); } @@ -23877,7 +25428,7 @@ function getRenderTargetSamples( renderTarget ) { - return Math.min( maxSamples, renderTarget.samples ); + return Math.min( capabilities.maxSamples, renderTarget.samples ); } @@ -23906,17 +25457,17 @@ function verifyColorSpace( texture, image ) { - const encoding = texture.encoding; + const colorSpace = texture.colorSpace; const format = texture.format; const type = texture.type; if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - if ( encoding !== LinearEncoding ) { + if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { // sRGB - if ( encoding === sRGBEncoding ) { + if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { if ( isWebGL2 === false ) { @@ -23953,7 +25504,7 @@ } else { - console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding ); + console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); } @@ -23986,24 +25537,26 @@ const isWebGL2 = capabilities.isWebGL2; - function convert( p, encoding = null ) { + function convert( p, colorSpace = NoColorSpace ) { let extension; - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; + const transfer = ColorManagement.getTransfer( colorSpace ); - if ( p === ByteType ) return 5120; - if ( p === ShortType ) return 5122; - if ( p === UnsignedShortType ) return 5123; - if ( p === IntType ) return 5124; - if ( p === UnsignedIntType ) return 5125; - if ( p === FloatType ) return 5126; + if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; + if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; + + if ( p === ByteType ) return gl.BYTE; + if ( p === ShortType ) return gl.SHORT; + if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; + if ( p === IntType ) return gl.INT; + if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; + if ( p === FloatType ) return gl.FLOAT; if ( p === HalfFloatType ) { - if ( isWebGL2 ) return 5131; + if ( isWebGL2 ) return gl.HALF_FLOAT; extension = extensions.get( 'OES_texture_half_float' ); @@ -24019,21 +25572,12 @@ } - if ( p === AlphaFormat ) return 6406; - if ( p === RGBAFormat ) return 6408; - if ( p === LuminanceFormat ) return 6409; - if ( p === LuminanceAlphaFormat ) return 6410; - if ( p === DepthFormat ) return 6402; - if ( p === DepthStencilFormat ) return 34041; - - // @deprecated since r137 - - if ( p === RGBFormat ) { - - console.warn( 'THREE.WebGLRenderer: THREE.RGBFormat has been removed. Use THREE.RGBAFormat instead. https://github.com/mrdoob/three.js/pull/23228' ); - return 6408; - - } + if ( p === AlphaFormat ) return gl.ALPHA; + if ( p === RGBAFormat ) return gl.RGBA; + if ( p === LuminanceFormat ) return gl.LUMINANCE; + if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; + if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; + if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; // WebGL 1 sRGB fallback @@ -24055,17 +25599,17 @@ // WebGL2 formats. - if ( p === RedFormat ) return 6403; - if ( p === RedIntegerFormat ) return 36244; - if ( p === RGFormat ) return 33319; - if ( p === RGIntegerFormat ) return 33320; - if ( p === RGBAIntegerFormat ) return 36249; + if ( p === RedFormat ) return gl.RED; + if ( p === RedIntegerFormat ) return gl.RED_INTEGER; + if ( p === RGFormat ) return gl.RG; + if ( p === RGIntegerFormat ) return gl.RG_INTEGER; + if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; // S3TC if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - if ( encoding === sRGBEncoding ) { + if ( transfer === SRGBTransfer ) { extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); @@ -24150,8 +25694,8 @@ if ( extension !== null ) { - if ( p === RGB_ETC2_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; + if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; } else { @@ -24173,20 +25717,20 @@ if ( extension !== null ) { - if ( p === RGBA_ASTC_4x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; } else { @@ -24198,13 +25742,36 @@ // BPTC - if ( p === RGBA_BPTC_Format ) { + if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { extension = extensions.get( 'EXT_texture_compression_bptc' ); if ( extension !== null ) { - if ( p === RGBA_BPTC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; + if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; + + } else { + + return null; + + } + + } + + // RGTC + + if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { + + extension = extensions.get( 'EXT_texture_compression_rgtc' ); + + if ( extension !== null ) { + + if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; + if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; + if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; + if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; } else { @@ -24218,7 +25785,7 @@ if ( p === UnsignedInt248Type ) { - if ( isWebGL2 ) return 34042; + if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; extension = extensions.get( 'WEBGL_depth_texture' ); @@ -24440,6 +26007,7 @@ joint.matrix.fromArray( jointPose.transform.matrix ); joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); + joint.matrixWorldNeedsUpdate = true; joint.jointRadius = jointPose.radius; } @@ -24488,6 +26056,7 @@ grip.matrix.fromArray( gripPose.transform.matrix ); grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); + grip.matrixWorldNeedsUpdate = true; if ( gripPose.linearVelocity ) { @@ -24532,6 +26101,7 @@ targetRay.matrix.fromArray( inputPose.transform.matrix ); targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); + targetRay.matrixWorldNeedsUpdate = true; if ( inputPose.linearVelocity ) { @@ -24607,38 +26177,6 @@ } - class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isDepthTexture = true; - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - } - - - } - class WebXRManager extends EventDispatcher { constructor( renderer, gl ) { @@ -24648,10 +26186,13 @@ const scope = this; let session = null; + let framebufferScaleFactor = 1.0; let referenceSpace = null; let referenceSpaceType = 'local-floor'; + // Set default foveation to maximum. + let foveation = 1.0; let customReferenceSpace = null; let pose = null; @@ -24666,8 +26207,8 @@ const controllers = []; const controllerInputSources = []; - const planes = new Set(); - const planesLastChangedTimes = new Map(); + const currentSize = new Vector2(); + let currentPixelRatio = null; // @@ -24681,9 +26222,9 @@ const cameras = [ cameraL, cameraR ]; - const cameraVR = new ArrayCamera(); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); + const cameraXR = new ArrayCamera(); + cameraXR.layers.enable( 1 ); + cameraXR.layers.enable( 2 ); let _currentDepthNear = null; let _currentDepthFar = null; @@ -24756,6 +26297,7 @@ if ( controller !== undefined ) { + controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); controller.dispatchEvent( { type: event.type, data: event.inputSource } ); } @@ -24804,6 +26346,9 @@ scope.isPresenting = false; + renderer.setPixelRatio( currentPixelRatio ); + renderer.setSize( currentSize.width, currentSize.height, false ); + scope.dispatchEvent( { type: 'sessionend' } ); } @@ -24891,11 +26436,14 @@ } + currentPixelRatio = renderer.getPixelRatio(); + renderer.getSize( currentSize ); + if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { const layerInit = { antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: attributes.alpha, + alpha: true, depth: attributes.depth, stencil: attributes.stencil, framebufferScaleFactor: framebufferScaleFactor @@ -24905,13 +26453,16 @@ session.updateRenderState( { baseLayer: glBaseLayer } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); + newRenderTarget = new WebGLRenderTarget( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, { format: RGBAFormat, type: UnsignedByteType, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, stencilBuffer: attributes.stencil } ); @@ -24924,14 +26475,14 @@ if ( attributes.depth ) { - glDepthFormat = attributes.stencil ? 35056 : 33190; + glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; } const projectionlayerInit = { - colorFormat: 32856, + colorFormat: gl.RGBA8, depthFormat: glDepthFormat, scaleFactor: framebufferScaleFactor }; @@ -24942,6 +26493,9 @@ session.updateRenderState( { layers: [ glProjLayer ] } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); + newRenderTarget = new WebGLRenderTarget( glProjLayer.textureWidth, glProjLayer.textureHeight, @@ -24950,7 +26504,7 @@ type: UnsignedByteType, depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), stencilBuffer: attributes.stencil, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, samples: attributes.antialias ? 4 : 0 } ); @@ -24961,8 +26515,7 @@ newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - // Set foveation to maximum. - this.setFoveation( 1.0 ); + this.setFoveation( foveation ); customReferenceSpace = null; referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); @@ -24978,6 +26531,16 @@ }; + this.getEnvironmentBlendMode = function () { + + if ( session !== null ) { + + return session.environmentBlendMode; + + } + + }; + function onInputSourcesChange( event ) { // Notify disconnected @@ -25101,6 +26664,7 @@ const bottom2 = bottomFov * far / far2 * near2; camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); } @@ -25124,114 +26688,122 @@ if ( session === null ) return; - cameraVR.near = cameraR.near = cameraL.near = camera.near; - cameraVR.far = cameraR.far = cameraL.far = camera.far; + cameraXR.near = cameraR.near = cameraL.near = camera.near; + cameraXR.far = cameraR.far = cameraL.far = camera.far; - if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { + if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { // Note that the new renderState won't apply until the next frame. See #18320 session.updateRenderState( { - depthNear: cameraVR.near, - depthFar: cameraVR.far + depthNear: cameraXR.near, + depthFar: cameraXR.far } ); - _currentDepthNear = cameraVR.near; - _currentDepthFar = cameraVR.far; + _currentDepthNear = cameraXR.near; + _currentDepthFar = cameraXR.far; + + } + + const parent = camera.parent; + const cameras = cameraXR.cameras; + + updateCamera( cameraXR, parent ); + + for ( let i = 0; i < cameras.length; i ++ ) { + + updateCamera( cameras[ i ], parent ); + + } + + // update projection matrix for proper view frustum culling - } + if ( cameras.length === 2 ) { - const parent = camera.parent; - const cameras = cameraVR.cameras; + setProjectionFromUnion( cameraXR, cameraL, cameraR ); - updateCamera( cameraVR, parent ); + } else { - for ( let i = 0; i < cameras.length; i ++ ) { + // assume single camera setup (AR) - updateCamera( cameras[ i ], parent ); + cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); } - cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); - // update user camera and its children - camera.matrix.copy( cameraVR.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + updateUserCamera( camera, cameraXR, parent ); - const children = camera.children; + }; - for ( let i = 0, l = children.length; i < l; i ++ ) { + function updateUserCamera( camera, cameraXR, parent ) { - children[ i ].updateMatrixWorld( true ); + if ( parent === null ) { - } + camera.matrix.copy( cameraXR.matrixWorld ); - // update projection matrix for proper view frustum culling + } else { - if ( cameras.length === 2 ) { + camera.matrix.copy( parent.matrixWorld ); + camera.matrix.invert(); + camera.matrix.multiply( cameraXR.matrixWorld ); - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + } - } else { + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + camera.updateMatrixWorld( true ); - // assume single camera setup (AR) + camera.projectionMatrix.copy( cameraXR.projectionMatrix ); + camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); + if ( camera.isPerspectiveCamera ) { + + camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); + camera.zoom = 1; } - }; + } this.getCamera = function () { - return cameraVR; + return cameraXR; }; this.getFoveation = function () { - if ( glProjLayer !== null ) { - - return glProjLayer.fixedFoveation; - - } - - if ( glBaseLayer !== null ) { + if ( glProjLayer === null && glBaseLayer === null ) { - return glBaseLayer.fixedFoveation; + return undefined; } - return undefined; + return foveation; }; - this.setFoveation = function ( foveation ) { + this.setFoveation = function ( value ) { // 0 = no foveation = full resolution // 1 = maximum foveation = the edges render at lower resolution + foveation = value; + if ( glProjLayer !== null ) { - glProjLayer.fixedFoveation = foveation; + glProjLayer.fixedFoveation = value; } if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - glBaseLayer.fixedFoveation = foveation; + glBaseLayer.fixedFoveation = value; } }; - this.getPlanes = function () { - - return planes; - - }; - // Animation Loop let onAnimationFrameCallback = null; @@ -25252,14 +26824,14 @@ } - let cameraVRNeedsUpdate = false; + let cameraXRNeedsUpdate = false; - // check if it's necessary to rebuild cameraVR's camera list + // check if it's necessary to rebuild cameraXR's camera list - if ( views.length !== cameraVR.cameras.length ) { + if ( views.length !== cameraXR.cameras.length ) { - cameraVR.cameras.length = 0; - cameraVRNeedsUpdate = true; + cameraXR.cameras.length = 0; + cameraXRNeedsUpdate = true; } @@ -25304,18 +26876,21 @@ } camera.matrix.fromArray( view.transform.matrix ); + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); camera.projectionMatrix.fromArray( view.projectionMatrix ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); if ( i === 0 ) { - cameraVR.matrix.copy( camera.matrix ); + cameraXR.matrix.copy( camera.matrix ); + cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); } - if ( cameraVRNeedsUpdate === true ) { + if ( cameraXRNeedsUpdate === true ) { - cameraVR.cameras.push( camera ); + cameraXR.cameras.push( camera ); } @@ -25342,60 +26917,7 @@ if ( frame.detectedPlanes ) { - scope.dispatchEvent( { type: 'planesdetected', data: frame.detectedPlanes } ); - - let planesToRemove = null; - - for ( const plane of planes ) { - - if ( ! frame.detectedPlanes.has( plane ) ) { - - if ( planesToRemove === null ) { - - planesToRemove = []; - - } - - planesToRemove.push( plane ); - - } - - } - - if ( planesToRemove !== null ) { - - for ( const plane of planesToRemove ) { - - planes.delete( plane ); - planesLastChangedTimes.delete( plane ); - scope.dispatchEvent( { type: 'planeremoved', data: plane } ); - - } - - } - - for ( const plane of frame.detectedPlanes ) { - - if ( ! planes.has( plane ) ) { - - planes.add( plane ); - planesLastChangedTimes.set( plane, frame.lastChangedTime ); - scope.dispatchEvent( { type: 'planeadded', data: plane } ); - - } else { - - const lastKnownTime = planesLastChangedTimes.get( plane ); - - if ( plane.lastChangedTime > lastKnownTime ) { - - planesLastChangedTimes.set( plane, plane.lastChangedTime ); - scope.dispatchEvent( { type: 'planechanged', data: plane } ); - - } - - } - - } + scope.dispatchEvent( { type: 'planesdetected', data: frame } ); } @@ -25421,6 +26943,18 @@ function WebGLMaterials( renderer, properties ) { + function refreshTransformUniform( map, uniform ) { + + if ( map.matrixAutoUpdate === true ) { + + map.updateMatrix(); + + } + + uniform.value.copy( map.matrix ); + + } + function refreshFogUniforms( uniforms, fog ) { fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); @@ -25538,25 +27072,56 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } 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; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + + if ( material.side === BackSide ) { + + uniforms.bumpScale.value *= - 1; + + } + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + + refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); + + uniforms.normalScale.value.copy( material.normalScale ); + + if ( material.side === BackSide ) { + + 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; @@ -25566,13 +27131,7 @@ uniforms.emissiveMap.value = material.emissiveMap; - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); } @@ -25580,6 +27139,8 @@ uniforms.specularMap.value = material.specularMap; + refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25607,10 +27168,12 @@ uniforms.lightMap.value = material.lightMap; // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer.physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; + refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); + } if ( material.aoMap ) { @@ -25618,175 +27181,27 @@ uniforms.aoMap.value = material.aoMap; uniforms.aoMapIntensity.value = material.aoMapIntensity; - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. displacementMap map - // 4. normal map - // 5. bump map - // 6. roughnessMap map - // 7. metalnessMap map - // 8. alphaMap map - // 9. emissiveMap map - // 10. clearcoat map - // 11. clearcoat normal map - // 12. clearcoat roughnessMap map - // 13. iridescence map - // 14. iridescence thickness map - // 15. specular intensity map - // 16. specular tint map - // 17. transmission map - // 18. thickness map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.roughnessMap ) { - - uvScaleMap = material.roughnessMap; - - } else if ( material.metalnessMap ) { - - uvScaleMap = material.metalnessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } else if ( material.clearcoatMap ) { - - uvScaleMap = material.clearcoatMap; - - } else if ( material.clearcoatNormalMap ) { - - uvScaleMap = material.clearcoatNormalMap; - - } else if ( material.clearcoatRoughnessMap ) { - - uvScaleMap = material.clearcoatRoughnessMap; - - } else if ( material.iridescenceMap ) { - - uvScaleMap = material.iridescenceMap; - - } else if ( material.iridescenceThicknessMap ) { - - uvScaleMap = material.iridescenceThicknessMap; - - } else if ( material.specularIntensityMap ) { - - uvScaleMap = material.specularIntensityMap; - - } else if ( material.specularColorMap ) { - - uvScaleMap = material.specularColorMap; - - } else if ( material.transmissionMap ) { - - uvScaleMap = material.transmissionMap; - - } else if ( material.thicknessMap ) { - - uvScaleMap = material.thicknessMap; - - } else if ( material.sheenColorMap ) { - - uvScaleMap = material.sheenColorMap; - - } else if ( material.sheenRoughnessMap ) { - - uvScaleMap = material.sheenRoughnessMap; - - } - - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); + refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); } - // uv repeat and offset setting priorities for uv2 - // 1. ao map - // 2. light map - - let uv2ScaleMap; - - if ( material.aoMap ) { - - uv2ScaleMap = material.aoMap; - - } else if ( material.lightMap ) { - - uv2ScaleMap = material.lightMap; - - } - - if ( uv2ScaleMap !== undefined ) { - - // backwards compatibility - if ( uv2ScaleMap.isWebGLRenderTarget ) { - - uv2ScaleMap = uv2ScaleMap.texture; + } - } + function refreshUniformsLine( uniforms, material ) { - if ( uv2ScaleMap.matrixAutoUpdate === true ) { + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - uv2ScaleMap.updateMatrix(); + if ( material.map ) { - } + uniforms.map.value = material.map; - uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); + refreshTransformUniform( material.map, uniforms.mapTransform ); } } - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } - function refreshUniformsDash( uniforms, material ) { uniforms.dashSize.value = material.dashSize; @@ -25806,12 +27221,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.uvTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25820,34 +27239,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsSprites( uniforms, material ) { @@ -25860,12 +27251,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25874,34 +27269,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsPhong( uniforms, material ) { @@ -25923,18 +27290,23 @@ function refreshUniformsStandard( uniforms, material ) { - uniforms.roughness.value = material.roughness; uniforms.metalness.value = material.metalness; - if ( material.roughnessMap ) { + if ( material.metalnessMap ) { - uniforms.roughnessMap.value = material.roughnessMap; + uniforms.metalnessMap.value = material.metalnessMap; + + refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); } - if ( material.metalnessMap ) { + uniforms.roughness.value = material.roughness; - uniforms.metalnessMap.value = material.metalnessMap; + if ( material.roughnessMap ) { + + uniforms.roughnessMap.value = material.roughnessMap; + + refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); } @@ -25963,12 +27335,16 @@ uniforms.sheenColorMap.value = material.sheenColorMap; + refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); + } if ( material.sheenRoughnessMap ) { uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; + refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); + } } @@ -25982,19 +27358,26 @@ 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.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; + refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); + + uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); + if ( material.side === BackSide ) { uniforms.clearcoatNormalScale.value.negate(); @@ -26016,12 +27399,16 @@ uniforms.iridescenceMap.value = material.iridescenceMap; + refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); + } if ( material.iridescenceThicknessMap ) { uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; + refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); + } } @@ -26036,6 +27423,8 @@ uniforms.transmissionMap.value = material.transmissionMap; + refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); + } uniforms.thickness.value = material.thickness; @@ -26044,6 +27433,8 @@ uniforms.thicknessMap.value = material.thicknessMap; + refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); + } uniforms.attenuationDistance.value = material.attenuationDistance; @@ -26051,18 +27442,36 @@ } + 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.specularIntensityMap ) { + if ( material.specularColorMap ) { - uniforms.specularIntensityMap.value = material.specularIntensityMap; + uniforms.specularColorMap.value = material.specularColorMap; + + refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform ); } - if ( material.specularColorMap ) { + if ( material.specularIntensityMap ) { - uniforms.specularColorMap.value = material.specularColorMap; + uniforms.specularIntensityMap.value = material.specularIntensityMap; + + refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform ); } @@ -26080,9 +27489,11 @@ function refreshUniformsDistance( uniforms, material ) { - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; + const light = properties.get( material ).light; + + uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); + uniforms.nearDistance.value = light.shadow.camera.near; + uniforms.farDistance.value = light.shadow.camera.far; } @@ -26099,7 +27510,7 @@ let updateList = {}; let allocatedBindingPoints = []; - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( 35375 ) : 0; // binding points are global whereas block indices are per shader program + const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program function bind( uniformsGroup, program ) { @@ -26153,10 +27564,10 @@ const size = uniformsGroup.__size; const usage = uniformsGroup.usage; - gl.bindBuffer( 35345, buffer ); - gl.bufferData( 35345, size, usage ); - gl.bindBuffer( 35345, null ); - gl.bindBufferBase( 35345, bindingPointIndex, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); + gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); + gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); return buffer; @@ -26187,50 +27598,64 @@ const uniforms = uniformsGroup.uniforms; const cache = uniformsGroup.__cache; - gl.bindBuffer( 35345, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - const uniform = uniforms[ i ]; + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // partly update the buffer if necessary + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - if ( hasUniformChanged( uniform, i, cache ) === true ) { + const uniform = uniformArray[ j ]; - const value = uniform.value; - const offset = uniform.__offset; + if ( hasUniformChanged( uniform, i, j, cache ) === true ) { - if ( typeof value === 'number' ) { + const offset = uniform.__offset; - uniform.__data[ 0 ] = value; - gl.bufferSubData( 35345, offset, uniform.__data ); + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - } else { + let arrayOffset = 0; - if ( uniform.value.isMatrix3 ) { + for ( let k = 0; k < values.length; k ++ ) { - // manually converting 3x3 to 3x4 + const value = values[ k ]; - uniform.__data[ 0 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 1 ] = uniform.value.elements[ 1 ]; - uniform.__data[ 2 ] = uniform.value.elements[ 2 ]; - uniform.__data[ 3 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 4 ] = uniform.value.elements[ 3 ]; - uniform.__data[ 5 ] = uniform.value.elements[ 4 ]; - uniform.__data[ 6 ] = uniform.value.elements[ 5 ]; - uniform.__data[ 7 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 8 ] = uniform.value.elements[ 6 ]; - uniform.__data[ 9 ] = uniform.value.elements[ 7 ]; - uniform.__data[ 10 ] = uniform.value.elements[ 8 ]; - uniform.__data[ 11 ] = uniform.value.elements[ 0 ]; + const info = getUniformSize( value ); - } else { + // TODO add integer and struct support + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + uniform.__data[ 0 ] = value; + gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); - value.toArray( uniform.__data ); + } else if ( value.isMatrix3 ) { + + // manually converting 3x3 to 3x4 + + 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; + + } } - gl.bufferSubData( 35345, offset, uniform.__data ); + gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); } @@ -26238,25 +27663,26 @@ } - gl.bindBuffer( 35345, null ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); } - function hasUniformChanged( uniform, index, cache ) { + function hasUniformChanged( uniform, index, indexArray, cache ) { const value = uniform.value; + const indexString = index + '_' + indexArray; - if ( cache[ index ] === undefined ) { + if ( cache[ indexString ] === undefined ) { // cache entry does not exist so far - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - cache[ index ] = value; + cache[ indexString ] = value; } else { - cache[ index ] = value.clone(); + cache[ indexString ] = value.clone(); } @@ -26264,21 +27690,21 @@ } else { + const cachedObject = cache[ indexString ]; + // compare current value with cached entry - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - if ( cache[ index ] !== value ) { + if ( cachedObject !== value ) { - cache[ index ] = value; + cache[ indexString ] = value; return true; } } else { - const cachedObject = cache[ index ]; - if ( cachedObject.equals( value ) === false ) { cachedObject.copy( value ); @@ -26303,1305 +27729,1659 @@ let offset = 0; // global buffer offset in bytes const chunkSize = 16; // size of a chunk in bytes - let chunkOffset = 0; // offset within a single chunk in bytes for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - const uniform = uniforms[ i ]; - const info = getUniformSize( uniform ); + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // the following two properties will be used for partial buffer updates + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; + const uniform = uniformArray[ j ]; - // + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; + + for ( let k = 0, kl = values.length; k < kl; k ++ ) { - if ( i > 0 ) { + const value = values[ k ]; - chunkOffset = offset % chunkSize; + const info = getUniformSize( value ); - const remainingSizeInChunk = chunkSize - chunkOffset; + // Calculate the chunk offset + const chunkOffsetUniform = offset % chunkSize; - // check for chunk overflow + // Check for chunk overflow + if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { - if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) { + // Add padding and adjust offset + offset += ( chunkSize - chunkOffsetUniform ); - // add padding and adjust offset + } + + // the following two properties will be used for partial buffer updates - offset += ( chunkSize - chunkOffset ); + uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); uniform.__offset = offset; + + // Update the global offset + offset += info.storage; + + } } - offset += info.storage; - } // ensure correct final padding - chunkOffset = offset % chunkSize; + const chunkOffset = offset % chunkSize; + + if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); + + // + + uniformsGroup.__size = offset; + uniformsGroup.__cache = {}; + + return this; + + } + + function getUniformSize( value ) { + + const info = { + boundary: 0, // bytes + storage: 0 // bytes + }; + + // determine sizes according to STD140 + + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + // float/int/bool + + info.boundary = 4; + info.storage = 4; + + } else if ( value.isVector2 ) { + + // vec2 + + info.boundary = 8; + info.storage = 8; + + } else if ( value.isVector3 || value.isColor ) { + + // 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 ) { + + // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + + info.boundary = 48; + info.storage = 48; + + } else if ( value.isMatrix4 ) { + + // mat4 + + info.boundary = 64; + info.storage = 64; + + } else if ( value.isTexture ) { + + console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + + } else { + + console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + + } + + return info; + + } + + function onUniformsGroupsDispose( event ) { + + const uniformsGroup = event.target; + + uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + + const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); + allocatedBindingPoints.splice( index, 1 ); + + gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + + delete buffers[ uniformsGroup.id ]; + delete updateList[ uniformsGroup.id ]; + + } + + function dispose() { + + for ( const id in buffers ) { + + 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 = true, + alpha = false, + antialias = false, + premultipliedAlpha = true, + preserveDrawingBuffer = false, + powerPreference = 'default', + failIfMajorPerformanceCaveat = false, + } = parameters; + + this.isWebGLRenderer = true; + + let _alpha; + + if ( context !== null ) { + + _alpha = context.getContextAttributes().alpha; + + } else { + + _alpha = alpha; + + } + + const uintClearColor = new Uint32Array( 4 ); + const intClearColor = new Int32Array( 4 ); + + let currentRenderList = null; + let currentRenderState = null; + + // render() can be called from within a callback triggered by another render. + // We track this so that the nested render call gets its list and state isolated from the parent render call. + + const renderListStack = []; + const renderStateStack = []; + + // public properties + + this.domElement = canvas; + + // Debug configuration container + this.debug = { + + /** + * 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; + + // physically based shading + + this._outputColorSpace = SRGBColorSpace; + + // physical lights + + this._useLegacyLights = false; + + // tone mapping + + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; + + // internal properties + + const _this = this; + + let _isContextLost = false; + + // internal state cache + + let _currentActiveCubeFace = 0; + let _currentActiveMipmapLevel = 0; + let _currentRenderTarget = null; + let _currentMaterialId = - 1; + + let _currentCamera = null; + + const _currentViewport = new Vector4(); + const _currentScissor = new Vector4(); + let _currentScissorTest = null; + + const _currentClearColor = new Color( 0x000000 ); + let _currentClearAlpha = 0; + + // + + let _width = canvas.width; + let _height = canvas.height; + + let _pixelRatio = 1; + let _opaqueSort = null; + let _transparentSort = null; + + const _viewport = new Vector4( 0, 0, _width, _height ); + const _scissor = new Vector4( 0, 0, _width, _height ); + let _scissorTest = false; + + // frustum + + const _frustum = new Frustum(); + + // clipping + + let _clippingEnabled = false; + let _localClippingEnabled = false; + + // transmission + + let _transmissionRenderTarget = null; + + // camera matrices cache + + const _projScreenMatrix = new Matrix4(); + + const _vector2 = new Vector2(); + const _vector3 = new Vector3(); + + const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + + function getTargetPixelRatio() { + + return _currentRenderTarget === null ? _pixelRatio : 1; + + } + + // initialize + + let _gl = context; + + function getContext( contextNames, contextAttributes ) { + + for ( let i = 0; i < contextNames.length; i ++ ) { + + const contextName = contextNames[ i ]; + const context = canvas.getContext( contextName, contextAttributes ); + if ( context !== null ) return context; + + } + + return null; + + } + + try { + + const contextAttributes = { + alpha: true, + depth, + stencil, + antialias, + premultipliedAlpha, + preserveDrawingBuffer, + powerPreference, + failIfMajorPerformanceCaveat, + }; + + // OffscreenCanvas does not have setAttribute, see #22811 + if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + + // event listeners must be registered before WebGL context is created, see #12753 + canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + + if ( _gl === null ) { + + const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + + if ( _this.isWebGL1Renderer === true ) { + + contextNames.shift(); + + } + + _gl = getContext( contextNames, contextAttributes ); + + if ( _gl === null ) { + + if ( getContext( contextNames ) ) { + + throw new Error( 'Error creating WebGL context with your selected attributes.' ); + + } else { + + throw new Error( 'Error creating WebGL context.' ); + + } + + } + + } + + if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 + + console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); + + } + + // Some experimental-webgl implementations do not have getShaderPrecisionFormat + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function () { + + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + + }; + + } - if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); + } catch ( error ) { - // + console.error( 'THREE.WebGLRenderer: ' + error.message ); + throw error; - uniformsGroup.__size = offset; - uniformsGroup.__cache = {}; + } - return this; + let extensions, capabilities, state, info; + let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; + let programCache, materials, renderLists, renderStates, clipping, shadowMap; - } + let background, morphtargets, bufferRenderer, indexedBufferRenderer; - function getUniformSize( uniform ) { + let utils, bindingStates, uniformsGroups; - const value = uniform.value; + function initGLContext() { - const info = { - boundary: 0, // bytes - storage: 0 // bytes - }; + extensions = new WebGLExtensions( _gl ); - // determine sizes according to STD140 + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - if ( typeof value === 'number' ) { + extensions.init( capabilities ); - // float/int + utils = new WebGLUtils( _gl, extensions, capabilities ); - info.boundary = 4; - info.storage = 4; + state = new WebGLState( _gl, extensions, capabilities ); - } else if ( value.isVector2 ) { + info = new WebGLInfo( _gl ); + properties = new WebGLProperties(); + textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); + cubemaps = new WebGLCubeMaps( _this ); + cubeuvmaps = new WebGLCubeUVMaps( _this ); + attributes = new WebGLAttributes( _gl, capabilities ); + bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); + geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); + objects = new WebGLObjects( _gl, geometries, attributes, info ); + morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); + clipping = new WebGLClipping( properties ); + programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); + materials = new WebGLMaterials( _this, properties ); + renderLists = new WebGLRenderLists(); + renderStates = new WebGLRenderStates( extensions, capabilities ); + background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); + shadowMap = new WebGLShadowMap( _this, objects, capabilities ); + uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - // vec2 + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - info.boundary = 8; - info.storage = 8; + info.programs = programCache.programs; - } else if ( value.isVector3 || value.isColor ) { + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.shadowMap = shadowMap; + _this.state = state; + _this.info = info; - // vec3 + } - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes + initGLContext(); - } else if ( value.isVector4 ) { + // xr - // vec4 + const xr = new WebXRManager( _this, _gl ); - info.boundary = 16; - info.storage = 16; + this.xr = xr; - } else if ( value.isMatrix3 ) { + // API - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + this.getContext = function () { - info.boundary = 48; - info.storage = 48; + return _gl; - } else if ( value.isMatrix4 ) { + }; - // mat4 + this.getContextAttributes = function () { - info.boundary = 64; - info.storage = 64; + return _gl.getContextAttributes(); - } else if ( value.isTexture ) { + }; - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + this.forceContextLoss = function () { - } else { + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + }; - } + this.forceContextRestore = function () { - return info; + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.restoreContext(); - } + }; - function onUniformsGroupsDispose( event ) { + this.getPixelRatio = function () { - const uniformsGroup = event.target; + return _pixelRatio; - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + }; - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); + this.setPixelRatio = function ( value ) { - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + if ( value === undefined ) return; - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; + _pixelRatio = value; - } + this.setSize( _width, _height, false ); - function dispose() { + }; - for ( const id in buffers ) { + this.getSize = function ( target ) { - gl.deleteBuffer( buffers[ id ] ); + return target.set( _width, _height ); - } + }; - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; + this.setSize = function ( width, height, updateStyle = true ) { - } + if ( xr.isPresenting ) { - return { + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - bind: bind, - update: update, + } - dispose: dispose + _width = width; + _height = height; - }; + canvas.width = Math.floor( width * _pixelRatio ); + canvas.height = Math.floor( height * _pixelRatio ); - } + if ( updateStyle === true ) { - function createCanvasElement() { + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; + } - } + this.setViewport( 0, 0, width, height ); - function WebGLRenderer( parameters = {} ) { + }; - this.isWebGLRenderer = true; + this.getDrawingBufferSize = function ( target ) { - const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), - _context = parameters.context !== undefined ? parameters.context : null, + return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', - _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; + }; - let _alpha; + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - if ( _context !== null ) { + _width = width; + _height = height; - _alpha = _context.getContextAttributes().alpha; + _pixelRatio = pixelRatio; - } else { + canvas.width = Math.floor( width * pixelRatio ); + canvas.height = Math.floor( height * pixelRatio ); - _alpha = parameters.alpha !== undefined ? parameters.alpha : false; + this.setViewport( 0, 0, width, height ); - } + }; - let currentRenderList = null; - let currentRenderState = null; + this.getCurrentViewport = function ( target ) { - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. + return target.copy( _currentViewport ); - const renderListStack = []; - const renderStateStack = []; + }; - // public properties + this.getViewport = function ( target ) { - this.domElement = _canvas; + return target.copy( _viewport ); - // Debug configuration container - this.debug = { + }; - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true - }; + this.setViewport = function ( x, y, width, height ) { - // clearing + if ( x.isVector4 ) { - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + _viewport.set( x.x, x.y, x.z, x.w ); - // scene graph + } else { - this.sortObjects = true; + _viewport.set( x, y, width, height ); - // user-defined clipping + } - this.clippingPlanes = []; - this.localClippingEnabled = false; + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - // physically based shading + }; - this.outputEncoding = LinearEncoding; + this.getScissor = function ( target ) { - // physical lights + return target.copy( _scissor ); - this.physicallyCorrectLights = false; + }; - // tone mapping + this.setScissor = function ( x, y, width, height ) { - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; + if ( x.isVector4 ) { - // internal properties + _scissor.set( x.x, x.y, x.z, x.w ); - const _this = this; + } else { - let _isContextLost = false; + _scissor.set( x, y, width, height ); - // internal state cache + } - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - let _currentCamera = null; + }; - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; + this.getScissorTest = function () { - // + return _scissorTest; - let _width = _canvas.width; - let _height = _canvas.height; + }; - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; + this.setScissorTest = function ( boolean ) { - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; + state.setScissorTest( _scissorTest = boolean ); - // frustum + }; - const _frustum = new Frustum(); + this.setOpaqueSort = function ( method ) { - // clipping + _opaqueSort = method; - let _clippingEnabled = false; - let _localClippingEnabled = false; + }; - // transmission + this.setTransparentSort = function ( method ) { - let _transmissionRenderTarget = null; + _transparentSort = method; - // camera matrices cache + }; - const _projScreenMatrix = new Matrix4(); + // Clearing - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); + this.getClearColor = function ( target ) { - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + return target.copy( background.getClearColor() ); - function getTargetPixelRatio() { + }; - return _currentRenderTarget === null ? _pixelRatio : 1; + this.setClearColor = function () { - } + background.setClearColor.apply( background, arguments ); - // initialize + }; - let _gl = _context; + this.getClearAlpha = function () { - function getContext( contextNames, contextAttributes ) { + return background.getClearAlpha(); - for ( let i = 0; i < contextNames.length; i ++ ) { + }; - const contextName = contextNames[ i ]; - const context = _canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; + this.setClearAlpha = function () { - } + background.setClearAlpha.apply( background, arguments ); - return null; + }; - } + this.clear = function ( color = true, depth = true, stencil = true ) { - try { + let bits = 0; - const contextAttributes = { - alpha: true, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference, - failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat - }; + if ( color ) { - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in _canvas ) _canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + // check if we're trying to clear an integer target + let isIntegerFormat = false; + if ( _currentRenderTarget !== null ) { - // event listeners must be registered before WebGL context is created, see #12753 - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + const targetFormat = _currentRenderTarget.texture.format; + isIntegerFormat = targetFormat === RGBAIntegerFormat || + targetFormat === RGIntegerFormat || + targetFormat === RedIntegerFormat; - if ( _gl === null ) { + } - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + // use the appropriate clear functions to clear the target if it's a signed + // or unsigned integer target + if ( isIntegerFormat ) { - if ( _this.isWebGL1Renderer === true ) { + const targetType = _currentRenderTarget.texture.type; + const isUnsignedType = targetType === UnsignedByteType || + targetType === UnsignedIntType || + targetType === UnsignedShortType || + targetType === UnsignedInt248Type || + targetType === UnsignedShort4444Type || + targetType === UnsignedShort5551Type; - contextNames.shift(); + const clearColor = background.getClearColor(); + const a = background.getClearAlpha(); + const r = clearColor.r; + const g = clearColor.g; + const b = clearColor.b; - } + if ( isUnsignedType ) { - _gl = getContext( contextNames, contextAttributes ); + uintClearColor[ 0 ] = r; + uintClearColor[ 1 ] = g; + uintClearColor[ 2 ] = b; + uintClearColor[ 3 ] = a; + _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor ); - if ( _gl === null ) { + } else { - if ( getContext( contextNames ) ) { + intClearColor[ 0 ] = r; + intClearColor[ 1 ] = g; + intClearColor[ 2 ] = b; + intClearColor[ 3 ] = a; + _gl.clearBufferiv( _gl.COLOR, 0, intClearColor ); - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + } } else { - throw new Error( 'Error creating WebGL context.' ); + bits |= _gl.COLOR_BUFFER_BIT; } } - } - - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil ) { - if ( _gl.getShaderPrecisionFormat === undefined ) { + bits |= _gl.STENCIL_BUFFER_BIT; + this.state.buffers.stencil.setMask( 0xffffffff ); - _gl.getShaderPrecisionFormat = function () { + } - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + _gl.clear( bits ); - }; + }; - } + this.clearColor = function () { - } catch ( error ) { + this.clear( true, false, false ); - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; + }; - } + this.clearDepth = function () { - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; + this.clear( false, true, false ); - let background, morphtargets, bufferRenderer, indexedBufferRenderer; + }; - let utils, bindingStates, uniformsGroups; + this.clearStencil = function () { - function initGLContext() { + this.clear( false, false, true ); - extensions = new WebGLExtensions( _gl ); + }; - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + // - extensions.init( capabilities ); + this.dispose = function () { - utils = new WebGLUtils( _gl, extensions, capabilities ); + canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - state = new WebGLState( _gl, extensions, capabilities ); + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + cubemaps.dispose(); + cubeuvmaps.dispose(); + objects.dispose(); + bindingStates.dispose(); + uniformsGroups.dispose(); + programCache.dispose(); - info = new WebGLInfo(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, _premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); + xr.dispose(); - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); + xr.removeEventListener( 'sessionstart', onXRSessionStart ); + xr.removeEventListener( 'sessionend', onXRSessionEnd ); - info.programs = programCache.programs; + if ( _transmissionRenderTarget ) { - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; + _transmissionRenderTarget.dispose(); + _transmissionRenderTarget = null; - } + } - initGLContext(); + animation.stop(); - // xr + }; - const xr = new WebXRManager( _this, _gl ); + // Events - this.xr = xr; + function onContextLost( event ) { - // API + event.preventDefault(); - this.getContext = function () { + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - return _gl; + _isContextLost = true; - }; + } - this.getContextAttributes = function () { + function onContextRestore( /* event */ ) { - return _gl.getContextAttributes(); + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - }; + _isContextLost = false; - this.forceContextLoss = function () { + const infoAutoReset = info.autoReset; + const shadowMapEnabled = shadowMap.enabled; + const shadowMapAutoUpdate = shadowMap.autoUpdate; + const shadowMapNeedsUpdate = shadowMap.needsUpdate; + const shadowMapType = shadowMap.type; - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + initGLContext(); - }; + info.autoReset = infoAutoReset; + shadowMap.enabled = shadowMapEnabled; + shadowMap.autoUpdate = shadowMapAutoUpdate; + shadowMap.needsUpdate = shadowMapNeedsUpdate; + shadowMap.type = shadowMapType; - this.forceContextRestore = function () { + } - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + function onContextCreationError( event ) { - }; + console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); - this.getPixelRatio = function () { + } - return _pixelRatio; + function onMaterialDispose( event ) { - }; + const material = event.target; - this.setPixelRatio = function ( value ) { + material.removeEventListener( 'dispose', onMaterialDispose ); - if ( value === undefined ) return; + deallocateMaterial( material ); - _pixelRatio = value; + } - this.setSize( _width, _height, false ); + // Buffer deallocation - }; + function deallocateMaterial( material ) { - this.getSize = function ( target ) { + releaseMaterialProgramReferences( material ); - return target.set( _width, _height ); + properties.remove( material ); - }; + } - this.setSize = function ( width, height, updateStyle ) { - if ( xr.isPresenting ) { + function releaseMaterialProgramReferences( material ) { - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + const programs = properties.get( material ).programs; - } + if ( programs !== undefined ) { - _width = width; - _height = height; + programs.forEach( function ( program ) { - _canvas.width = Math.floor( width * _pixelRatio ); - _canvas.height = Math.floor( height * _pixelRatio ); + programCache.releaseProgram( program ); - if ( updateStyle !== false ) { + } ); - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + if ( material.isShaderMaterial ) { - } + programCache.releaseShaderCache( material ); - this.setViewport( 0, 0, width, height ); + } - }; + } - this.getDrawingBufferSize = function ( target ) { + } - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); + // Buffer rendering - }; + this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - _width = width; - _height = height; + const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - _pixelRatio = pixelRatio; + const program = setProgram( camera, scene, geometry, material, object ); - _canvas.width = Math.floor( width * pixelRatio ); - _canvas.height = Math.floor( height * pixelRatio ); + state.setMaterial( material, frontFaceCW ); - this.setViewport( 0, 0, width, height ); + // - }; + let index = geometry.index; + let rangeFactor = 1; - this.getCurrentViewport = function ( target ) { + if ( material.wireframe === true ) { - return target.copy( _currentViewport ); + index = geometries.getWireframeAttribute( geometry ); - }; + if ( index === undefined ) return; - this.getViewport = function ( target ) { + rangeFactor = 2; - return target.copy( _viewport ); + } - }; + // - this.setViewport = function ( x, y, width, height ) { + const drawRange = geometry.drawRange; + const position = geometry.attributes.position; - if ( x.isVector4 ) { + let drawStart = drawRange.start * rangeFactor; + let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; - _viewport.set( x.x, x.y, x.z, x.w ); + if ( group !== null ) { - } else { + drawStart = Math.max( drawStart, group.start * rangeFactor ); + drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); - _viewport.set( x, y, width, height ); + } - } + if ( index !== null ) { - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, index.count ); - }; + } else if ( position !== undefined && position !== null ) { - this.getScissor = function ( target ) { + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, position.count ); - return target.copy( _scissor ); + } - }; + const drawCount = drawEnd - drawStart; - this.setScissor = function ( x, y, width, height ) { + if ( drawCount < 0 || drawCount === Infinity ) return; - if ( x.isVector4 ) { + // - _scissor.set( x.x, x.y, x.z, x.w ); + bindingStates.setup( object, material, program, geometry, index ); - } else { + let attribute; + let renderer = bufferRenderer; - _scissor.set( x, y, width, height ); + if ( index !== null ) { - } + attribute = attributes.get( index ); - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); - }; + } - this.getScissorTest = function () { + // - return _scissorTest; + if ( object.isMesh ) { - }; + if ( material.wireframe === true ) { - this.setScissorTest = function ( boolean ) { + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( _gl.LINES ); - state.setScissorTest( _scissorTest = boolean ); + } else { - }; + renderer.setMode( _gl.TRIANGLES ); - this.setOpaqueSort = function ( method ) { + } - _opaqueSort = method; + } else if ( object.isLine ) { - }; + let lineWidth = material.linewidth; - this.setTransparentSort = function ( method ) { + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - _transparentSort = method; + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - }; + if ( object.isLineSegments ) { - // Clearing + renderer.setMode( _gl.LINES ); - this.getClearColor = function ( target ) { + } else if ( object.isLineLoop ) { - return target.copy( background.getClearColor() ); + renderer.setMode( _gl.LINE_LOOP ); - }; + } else { - this.setClearColor = function () { + renderer.setMode( _gl.LINE_STRIP ); - background.setClearColor.apply( background, arguments ); + } - }; + } else if ( object.isPoints ) { - this.getClearAlpha = function () { + renderer.setMode( _gl.POINTS ); - return background.getClearAlpha(); + } else if ( object.isSprite ) { - }; + renderer.setMode( _gl.TRIANGLES ); - this.setClearAlpha = function () { + } - background.setClearAlpha.apply( background, arguments ); + if ( object.isBatchedMesh ) { - }; + renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); - this.clear = function ( color = true, depth = true, stencil = true ) { + } else if ( object.isInstancedMesh ) { - let bits = 0; + renderer.renderInstances( drawStart, drawCount, object.count ); - if ( color ) bits |= 16384; - if ( depth ) bits |= 256; - if ( stencil ) bits |= 1024; + } else if ( geometry.isInstancedBufferGeometry ) { - _gl.clear( bits ); + const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; + const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); - }; + renderer.renderInstances( drawStart, drawCount, instanceCount ); - this.clearColor = function () { + } else { - this.clear( true, false, false ); + renderer.render( drawStart, drawCount ); - }; + } - this.clearDepth = function () { + }; - this.clear( false, true, false ); + // Compile - }; + function prepareMaterial( material, scene, object ) { - this.clearStencil = function () { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - this.clear( false, false, true ); + material.side = BackSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - }; + material.side = FrontSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - // + material.side = DoubleSide; - this.dispose = function () { + } else { - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + getProgram( material, scene, object ); - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); + } - xr.dispose(); + } - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); + this.compile = function ( scene, camera, targetScene = null ) { - if ( _transmissionRenderTarget ) { + if ( targetScene === null ) targetScene = scene; - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; + currentRenderState = renderStates.get( targetScene ); + currentRenderState.init(); - } + renderStateStack.push( currentRenderState ); - animation.stop(); + // gather lights from both the target scene and the new object that will be added to the scene. - }; + targetScene.traverseVisible( function ( object ) { - // Events + if ( object.isLight && object.layers.test( camera.layers ) ) { - function onContextLost( event ) { + currentRenderState.pushLight( object ); - event.preventDefault(); + if ( object.castShadow ) { - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + currentRenderState.pushShadow( object ); - _isContextLost = true; + } - } + } - function onContextRestore( /* event */ ) { + } ); - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + if ( scene !== targetScene ) { - _isContextLost = false; + scene.traverseVisible( function ( object ) { - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; + if ( object.isLight && object.layers.test( camera.layers ) ) { - initGLContext(); + currentRenderState.pushLight( object ); - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; + if ( object.castShadow ) { - } + currentRenderState.pushShadow( object ); - function onContextCreationError( event ) { + } - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); + } - } + } ); - function onMaterialDispose( event ) { + } - const material = event.target; + currentRenderState.setupLights( _this._useLegacyLights ); - material.removeEventListener( 'dispose', onMaterialDispose ); + // Only initialize materials in the new scene, not the targetScene. - deallocateMaterial( material ); + const materials = new Set(); - } + scene.traverse( function ( object ) { - // Buffer deallocation + const material = object.material; - function deallocateMaterial( material ) { + if ( material ) { - releaseMaterialProgramReferences( material ); + if ( Array.isArray( material ) ) { - properties.remove( material ); + for ( let i = 0; i < material.length; i ++ ) { - } + const material2 = material[ i ]; + prepareMaterial( material2, targetScene, object ); + materials.add( material2 ); - function releaseMaterialProgramReferences( material ) { + } - const programs = properties.get( material ).programs; + } else { - if ( programs !== undefined ) { + prepareMaterial( material, targetScene, object ); + materials.add( material ); - programs.forEach( function ( program ) { + } - programCache.releaseProgram( program ); + } } ); - if ( material.isShaderMaterial ) { + renderStateStack.pop(); + currentRenderState = null; - programCache.releaseShaderCache( material ); + return materials; - } + }; - } + // compileAsync - } + this.compileAsync = function ( scene, camera, targetScene = null ) { - // Buffer rendering + const materials = this.compile( scene, camera, targetScene ); - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { + // Wait for all the materials in the new object to indicate that they're + // ready to be used before resolving the promise. - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) + return new Promise( ( resolve ) => { - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + function checkMaterialsReady() { - const program = setProgram( camera, scene, geometry, material, object ); + materials.forEach( function ( material ) { - state.setMaterial( material, frontFaceCW ); + const materialProperties = properties.get( material ); + const program = materialProperties.currentProgram; - // + if ( program.isReady() ) { - let index = geometry.index; - let rangeFactor = 1; + // remove any programs that report they're ready to use from the list + materials.delete( material ); - if ( material.wireframe === true ) { + } - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + } ); - } + // once the list of compiling materials is empty, call the callback - // + if ( materials.size === 0 ) { - const drawRange = geometry.drawRange; - const position = geometry.attributes.position; + resolve( scene ); + return; - let drawStart = drawRange.start * rangeFactor; - let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; + } - if ( group !== null ) { + // if some materials are still not ready, wait a bit and check again - drawStart = Math.max( drawStart, group.start * rangeFactor ); - drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); + setTimeout( checkMaterialsReady, 10 ); - } + } - if ( index !== null ) { + if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, index.count ); + // If we can check the compilation status of the materials without + // blocking then do so right away. - } else if ( position !== undefined && position !== null ) { + checkMaterialsReady(); - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, position.count ); + } else { - } + // Otherwise start by waiting a bit to give the materials we just + // initialized a chance to finish. - const drawCount = drawEnd - drawStart; + setTimeout( checkMaterialsReady, 10 ); - if ( drawCount < 0 || drawCount === Infinity ) return; + } - // + } ); - bindingStates.setup( object, material, program, geometry, index ); + }; - let attribute; - let renderer = bufferRenderer; + // Animation Loop - if ( index !== null ) { + let onAnimationFrameCallback = null; - attribute = attributes.get( index ); + function onAnimationFrame( time ) { - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); } - // + function onXRSessionStart() { - if ( object.isMesh ) { + animation.stop(); - if ( material.wireframe === true ) { + } - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); + function onXRSessionEnd() { - } else { + animation.start(); - renderer.setMode( 4 ); + } - } + const animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - } else if ( object.isLine ) { + if ( typeof self !== 'undefined' ) animation.setContext( self ); - let lineWidth = material.linewidth; + this.setAnimationLoop = function ( callback ) { - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + onAnimationFrameCallback = callback; + xr.setAnimationLoop( callback ); - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + ( callback === null ) ? animation.stop() : animation.start(); - if ( object.isLineSegments ) { + }; - renderer.setMode( 1 ); + xr.addEventListener( 'sessionstart', onXRSessionStart ); + xr.addEventListener( 'sessionend', onXRSessionEnd ); - } else if ( object.isLineLoop ) { + // Rendering - renderer.setMode( 2 ); + this.render = function ( scene, camera ) { - } else { + if ( camera !== undefined && camera.isCamera !== true ) { - renderer.setMode( 3 ); + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; } - } else if ( object.isPoints ) { - - renderer.setMode( 0 ); + if ( _isContextLost === true ) return; - } else if ( object.isSprite ) { + // update scene graph - renderer.setMode( 4 ); - - } - - if ( object.isInstancedMesh ) { + if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - renderer.renderInstances( drawStart, drawCount, object.count ); + // update camera matrices and frustum - } else if ( geometry.isInstancedBufferGeometry ) { + if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; - const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); + if ( xr.enabled === true && xr.isPresenting === true ) { - renderer.renderInstances( drawStart, drawCount, instanceCount ); + if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - } else { + camera = xr.getCamera(); // use XR camera for rendering - renderer.render( drawStart, drawCount ); + } - } + // + if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - }; + currentRenderState = renderStates.get( scene, renderStateStack.length ); + currentRenderState.init(); - // Compile + renderStateStack.push( currentRenderState ); - this.compile = function ( scene, camera ) { + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix ); - function prepare( material, scene, object ) { + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); - if ( material.transparent === true && material.side === DoubleSide ) { + currentRenderList = renderLists.get( scene, renderListStack.length ); + currentRenderList.init(); - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + renderListStack.push( currentRenderList ); - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + projectObject( scene, camera, 0, _this.sortObjects ); - material.side = DoubleSide; + currentRenderList.finish(); - } else { + if ( _this.sortObjects === true ) { - getProgram( material, scene, object ); + currentRenderList.sort( _opaqueSort, _transparentSort ); } - } + // - currentRenderState = renderStates.get( scene ); - currentRenderState.init(); + this.info.render.frame ++; - renderStateStack.push( currentRenderState ); + if ( _clippingEnabled === true ) clipping.beginShadows(); - scene.traverseVisible( function ( object ) { + const shadowsArray = currentRenderState.state.shadowsArray; - if ( object.isLight && object.layers.test( camera.layers ) ) { + shadowMap.render( shadowsArray, scene, camera ); - currentRenderState.pushLight( object ); + if ( _clippingEnabled === true ) clipping.endShadows(); - if ( object.castShadow ) { + // - currentRenderState.pushShadow( object ); + if ( this.info.autoReset === true ) this.info.reset(); - } - } + // - } ); + background.render( currentRenderList, scene ); - currentRenderState.setupLights( _this.physicallyCorrectLights ); + // render scene - scene.traverse( function ( object ) { + currentRenderState.setupLights( _this._useLegacyLights ); - const material = object.material; + if ( camera.isArrayCamera ) { - if ( material ) { + const cameras = camera.cameras; - if ( Array.isArray( material ) ) { + for ( let i = 0, l = cameras.length; i < l; i ++ ) { - for ( let i = 0; i < material.length; i ++ ) { + const camera2 = cameras[ i ]; - const material2 = material[ i ]; + renderScene( currentRenderList, scene, camera2, camera2.viewport ); - prepare( material2, scene, object ); + } - } + } else { - } else { + renderScene( currentRenderList, scene, camera ); - prepare( material, scene, object ); + } - } + // - } + if ( _currentRenderTarget !== null ) { - } ); + // resolve multisample renderbuffers to a single-sample texture if necessary - renderStateStack.pop(); - currentRenderState = null; + textures.updateMultisampleRenderTarget( _currentRenderTarget ); - }; + // Generate mipmap if we're using any kind of mipmap filtering - // Animation Loop + textures.updateRenderTargetMipmap( _currentRenderTarget ); - let onAnimationFrameCallback = null; + } - function onAnimationFrame( time ) { + // - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - } + // _gl.finish(); - function onXRSessionStart() { + bindingStates.resetDefaultState(); + _currentMaterialId = - 1; + _currentCamera = null; - animation.stop(); + renderStateStack.pop(); - } + if ( renderStateStack.length > 0 ) { - function onXRSessionEnd() { + currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - animation.start(); + } else { - } + currentRenderState = null; + + } - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + renderListStack.pop(); - if ( typeof self !== 'undefined' ) animation.setContext( self ); + if ( renderListStack.length > 0 ) { - this.setAnimationLoop = function ( callback ) { + currentRenderList = renderListStack[ renderListStack.length - 1 ]; - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); + } else { - ( callback === null ) ? animation.stop() : animation.start(); + currentRenderList = null; - }; + } - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); + }; - // Rendering + function projectObject( object, camera, groupOrder, sortObjects ) { - this.render = function ( scene, camera ) { + if ( object.visible === false ) return; - if ( camera !== undefined && camera.isCamera !== true ) { + const visible = object.layers.test( camera.layers ); - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + if ( visible ) { - } + if ( object.isGroup ) { - if ( _isContextLost === true ) return; + groupOrder = object.renderOrder; - // update scene graph + } else if ( object.isLOD ) { - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); + if ( object.autoUpdate === true ) object.update( camera ); - // update camera matrices and frustum + } else if ( object.isLight ) { - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); + currentRenderState.pushLight( object ); - if ( xr.enabled === true && xr.isPresenting === true ) { + if ( object.castShadow ) { - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); + currentRenderState.pushShadow( object ); - camera = xr.getCamera(); // use XR camera for rendering + } - } + } else if ( object.isSprite ) { - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); + if ( sortObjects ) { - renderStateStack.push( currentRenderState ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); + } - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + const geometry = objects.update( object ); + const material = object.material; - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); + if ( material.visible ) { - renderListStack.push( currentRenderList ); + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - projectObject( scene, camera, 0, _this.sortObjects ); + } - currentRenderList.finish(); + } - if ( _this.sortObjects === true ) { + } else if ( object.isMesh || object.isLine || object.isPoints ) { - currentRenderList.sort( _opaqueSort, _transparentSort ); + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - } + const geometry = objects.update( object ); + const material = object.material; - // + if ( sortObjects ) { - if ( _clippingEnabled === true ) clipping.beginShadows(); + if ( object.boundingSphere !== undefined ) { - const shadowsArray = currentRenderState.state.shadowsArray; + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + _vector3.copy( object.boundingSphere.center ); - shadowMap.render( shadowsArray, scene, camera ); + } else { - if ( _clippingEnabled === true ) clipping.endShadows(); + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + _vector3.copy( geometry.boundingSphere.center ); - // + } - if ( this.info.autoReset === true ) this.info.reset(); + _vector3 + .applyMatrix4( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - // + } - background.render( currentRenderList, scene ); + if ( Array.isArray( material ) ) { - // render scene + const groups = geometry.groups; - currentRenderState.setupLights( _this.physicallyCorrectLights ); + for ( let i = 0, l = groups.length; i < l; i ++ ) { - if ( camera.isArrayCamera ) { + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - const cameras = camera.cameras; + if ( groupMaterial && groupMaterial.visible ) { - for ( let i = 0, l = cameras.length; i < l; i ++ ) { + currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - const camera2 = cameras[ i ]; + } - renderScene( currentRenderList, scene, camera2, camera2.viewport ); + } - } + } else if ( material.visible ) { - } else { + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - renderScene( currentRenderList, scene, camera ); + } - } + } - // + } - if ( _currentRenderTarget !== null ) { + } - // resolve multisample renderbuffers to a single-sample texture if necessary + const children = object.children; - textures.updateMultisampleRenderTarget( _currentRenderTarget ); + for ( let i = 0, l = children.length; i < l; i ++ ) { - // Generate mipmap if we're using any kind of mipmap filtering + projectObject( children[ i ], camera, groupOrder, sortObjects ); - textures.updateRenderTargetMipmap( _currentRenderTarget ); + } } - // + function renderScene( currentRenderList, scene, camera, viewport ) { - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); + const opaqueObjects = currentRenderList.opaque; + const transmissiveObjects = currentRenderList.transmissive; + const transparentObjects = currentRenderList.transparent; - // _gl.finish(); + currentRenderState.setupLightsView( camera ); - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; + if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); - renderStateStack.pop(); + if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); - if ( renderStateStack.length > 0 ) { + if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; + if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); + if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); + if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - } else { + // Ensure depth buffer writing is enabled so it can be cleared on next render - currentRenderState = null; + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); - } + state.setPolygonOffset( false ); - renderListStack.pop(); + } - if ( renderListStack.length > 0 ) { + function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { - currentRenderList = renderListStack[ renderListStack.length - 1 ]; + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } else { + if ( overrideMaterial !== null ) { - currentRenderList = null; + return; - } + } - }; + const isWebGL2 = capabilities.isWebGL2; - function projectObject( object, camera, groupOrder, sortObjects ) { + if ( _transmissionRenderTarget === null ) { - if ( object.visible === false ) return; + _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { + generateMipmaps: true, + type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, + minFilter: LinearMipmapLinearFilter, + samples: ( isWebGL2 ) ? 4 : 0 + } ); - const visible = object.layers.test( camera.layers ); + // debug - if ( visible ) { + /* + const geometry = new PlaneGeometry(); + const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); - if ( object.isGroup ) { + const mesh = new Mesh( geometry, material ); + scene.add( mesh ); + */ - groupOrder = object.renderOrder; + } - } else if ( object.isLOD ) { + _this.getDrawingBufferSize( _vector2 ); - if ( object.autoUpdate === true ) object.update( camera ); + if ( isWebGL2 ) { - } else if ( object.isLight ) { + _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - currentRenderState.pushLight( object ); + } else { - if ( object.castShadow ) { + _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - currentRenderState.pushShadow( object ); + } - } + // - } else if ( object.isSprite ) { + const currentRenderTarget = _this.getRenderTarget(); + _this.setRenderTarget( _transmissionRenderTarget ); - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + _this.getClearColor( _currentClearColor ); + _currentClearAlpha = _this.getClearAlpha(); + if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); - if ( sortObjects ) { + _this.clear(); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + // 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; - } + renderObjects( opaqueObjects, scene, camera ); - const geometry = objects.update( object ); - const material = object.material; + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - if ( material.visible ) { + let renderTargetNeedsUpdate = false; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { - } + const renderItem = transmissiveObjects[ i ]; - } + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = renderItem.material; + const group = renderItem.group; - } else if ( object.isMesh || object.isLine || object.isPoints ) { + if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { - if ( object.isSkinnedMesh ) { + const currentSide = material.side; - // update skeleton only once in a frame + material.side = BackSide; + material.needsUpdate = true; - if ( object.skeleton.frame !== info.render.frame ) { + renderObject( object, scene, camera, geometry, material, group ); - object.skeleton.update(); - object.skeleton.frame = info.render.frame; + material.side = currentSide; + material.needsUpdate = true; - } + renderTargetNeedsUpdate = true; } - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - if ( sortObjects ) { + } - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + if ( renderTargetNeedsUpdate === true ) { - } + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - const geometry = objects.update( object ); - const material = object.material; + } - if ( Array.isArray( material ) ) { + _this.setRenderTarget( currentRenderTarget ); - const groups = geometry.groups; + _this.setClearColor( _currentClearColor, _currentClearAlpha ); - for ( let i = 0, l = groups.length; i < l; i ++ ) { + _this.toneMapping = currentToneMapping; - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; + } - if ( groupMaterial && groupMaterial.visible ) { + function renderObjects( renderList, scene, camera ) { - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } + for ( let i = 0, l = renderList.length; i < l; i ++ ) { - } + const renderItem = renderList[ i ]; - } else if ( material.visible ) { + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = overrideMaterial === null ? renderItem.material : overrideMaterial; + const group = renderItem.group; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + if ( object.layers.test( camera.layers ) ) { - } + renderObject( object, scene, camera, geometry, material, group ); } @@ -27609,1059 +29389,1045 @@ } - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + function renderObject( object, scene, camera, geometry, material, group ) { - projectObject( children[ i ], camera, groupOrder, sortObjects ); + object.onBeforeRender( _this, scene, camera, geometry, material, group ); - } + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - } + material.onBeforeRender( _this, scene, camera, geometry, object, group ); - function renderScene( currentRenderList, scene, camera, viewport ) { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; + material.side = BackSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - currentRenderState.setupLightsView( camera ); + material.side = FrontSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); + material.side = DoubleSide; - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); + } else { - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - // Ensure depth buffer writing is enabled so it can be cleared on next render + } - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + object.onAfterRender( _this, scene, camera, geometry, material, group ); - state.setPolygonOffset( false ); + } - } + function getProgram( material, scene, object ) { - function renderTransmissionPass( opaqueObjects, scene, camera ) { + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - const isWebGL2 = capabilities.isWebGL2; + const materialProperties = properties.get( material ); - if ( _transmissionRenderTarget === null ) { + const lights = currentRenderState.state.lights; + const shadowsArray = currentRenderState.state.shadowsArray; - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 && _antialias === true ) ? 4 : 0 - } ); + const lightsStateVersion = lights.state.version; - } + const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); + const programCacheKey = programCache.getProgramCacheKey( parameters ); - _this.getDrawingBufferSize( _vector2 ); + let programs = materialProperties.programs; - if ( isWebGL2 ) { + // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); + materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; + materialProperties.fog = scene.fog; + materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - } else { + if ( programs === undefined ) { - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); + // new material - } + material.addEventListener( 'dispose', onMaterialDispose ); - // + programs = new Map(); + materialProperties.programs = programs; - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - _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; + let program = programs.get( programCacheKey ); - renderObjects( opaqueObjects, scene, camera ); + if ( program !== undefined ) { - _this.toneMapping = currentToneMapping; + // early out if program and light state is identical - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); + if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - _this.setRenderTarget( currentRenderTarget ); + updateCommonMaterialProperties( material, parameters ); - } + return program; - function renderObjects( renderList, scene, camera ) { + } - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; + } else { - for ( let i = 0, l = renderList.length; i < l; i ++ ) { + parameters.uniforms = programCache.getUniforms( material ); - const renderItem = renderList[ i ]; + material.onBuild( object, parameters, _this ); - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; + material.onBeforeCompile( parameters, _this ); - if ( object.layers.test( camera.layers ) ) { + program = programCache.acquireProgram( parameters, programCacheKey ); + programs.set( programCacheKey, program ); - renderObject( object, scene, camera, geometry, material, group ); + materialProperties.uniforms = parameters.uniforms; } - } - - } + const uniforms = materialProperties.uniforms; - function renderObject( object, scene, camera, geometry, material, group ) { + if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - object.onBeforeRender( _this, scene, camera, geometry, material, group ); + uniforms.clippingPlanes = clipping.uniform; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + } - material.onBeforeRender( _this, scene, camera, geometry, object, group ); + updateCommonMaterialProperties( material, parameters ); - if ( material.transparent === true && material.side === DoubleSide ) { + // store the light setup it was created for - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + materialProperties.needsLights = materialNeedsLights( material ); + materialProperties.lightsStateVersion = lightsStateVersion; - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + if ( materialProperties.needsLights ) { - material.side = DoubleSide; + // wire up the material to this renderer's lighting state - } else { + 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; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + 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 - } + } - object.onAfterRender( _this, scene, camera, geometry, material, group ); + materialProperties.currentProgram = program; + materialProperties.uniformsList = null; - } + return program; - function getProgram( material, scene, object ) { + } - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + function getUniformList( materialProperties ) { - const materialProperties = properties.get( material ); + if ( materialProperties.uniformsList === null ) { - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; + const progUniforms = materialProperties.currentProgram.getUniforms(); + materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); - const lightsStateVersion = lights.state.version; + } - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); + return materialProperties.uniformsList; - let programs = materialProperties.programs; + } - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change + function updateCommonMaterialProperties( material, parameters ) { - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); + const materialProperties = properties.get( material ); - if ( programs === undefined ) { + materialProperties.outputColorSpace = parameters.outputColorSpace; + materialProperties.batching = parameters.batching; + materialProperties.instancing = parameters.instancing; + materialProperties.instancingColor = parameters.instancingColor; + 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; - // new material + } - material.addEventListener( 'dispose', onMaterialDispose ); + function setProgram( camera, scene, geometry, material, object ) { - programs = new Map(); - materialProperties.programs = programs; + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - } + textures.resetTextureUnits(); - let program = programs.get( programCacheKey ); + const fog = scene.fog; + const environment = material.isMeshStandardMaterial ? scene.environment : null; + const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); + const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); + const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; + const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); + const morphTargets = !! geometry.morphAttributes.position; + const morphNormals = !! geometry.morphAttributes.normal; + const morphColors = !! geometry.morphAttributes.color; - if ( program !== undefined ) { + let toneMapping = NoToneMapping; - // early out if program and light state is identical + if ( material.toneMapped ) { - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { + if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { - updateCommonMaterialProperties( material, parameters ); + toneMapping = _this.toneMapping; - return program; + } } - } else { + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - parameters.uniforms = programCache.getUniforms( material ); + const materialProperties = properties.get( material ); + const lights = currentRenderState.state.lights; - material.onBuild( object, parameters, _this ); + if ( _clippingEnabled === true ) { - material.onBeforeCompile( parameters, _this ); + if ( _localClippingEnabled === true || camera !== _currentCamera ) { - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); + const useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - materialProperties.uniforms = parameters.uniforms; + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + clipping.setState( material, camera, useCache ); - } + } - const uniforms = materialProperties.uniforms; + } - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { + // - uniforms.clippingPlanes = clipping.uniform; + let needsProgramChange = false; - } + if ( material.version === materialProperties.__version ) { - updateCommonMaterialProperties( material, parameters ); + if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - // store the light setup it was created for + needsProgramChange = true; - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; + } else if ( materialProperties.outputColorSpace !== colorSpace ) { - if ( materialProperties.needsLights ) { + needsProgramChange = true; - // wire up the material to this renderer's lighting state + } else if ( object.isBatchedMesh && materialProperties.batching === false ) { - 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; + needsProgramChange = true; - 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 + } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { - } + needsProgramChange = true; - const progUniforms = program.getUniforms(); - const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - materialProperties.currentProgram = program; - materialProperties.uniformsList = uniformsList; + needsProgramChange = true; - return program; + } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - } + needsProgramChange = true; - function updateCommonMaterialProperties( material, parameters ) { + } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - const materialProperties = properties.get( material ); + needsProgramChange = true; - materialProperties.outputEncoding = parameters.outputEncoding; - materialProperties.instancing = parameters.instancing; - 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; + } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - } + needsProgramChange = true; - function setProgram( camera, scene, geometry, material, object ) { + } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + needsProgramChange = true; - textures.resetTextureUnits(); + } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.encoding : LinearEncoding ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent; - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; + needsProgramChange = true; - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + } else if ( materialProperties.envMap !== envMap ) { - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; + needsProgramChange = true; - if ( _clippingEnabled === true ) { + } else if ( material.fog === true && materialProperties.fog !== fog ) { - if ( _localClippingEnabled === true || camera !== _currentCamera ) { + needsProgramChange = true; - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== clipping.numPlanes || + materialProperties.numIntersection !== clipping.numIntersection ) ) { - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); + needsProgramChange = true; - } + } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - } + needsProgramChange = true; - // + } else if ( materialProperties.vertexTangents !== vertexTangents ) { - let needsProgramChange = false; + needsProgramChange = true; - if ( material.version === materialProperties.__version ) { + } else if ( materialProperties.morphTargets !== morphTargets ) { - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphNormals !== morphNormals ) { - } else if ( materialProperties.outputEncoding !== encoding ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphColors !== morphColors ) { - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.toneMapping !== toneMapping ) { - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { + needsProgramChange = true; - needsProgramChange = true; + } - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { + } else { needsProgramChange = true; + materialProperties.__version = material.version; - } else if ( materialProperties.envMap !== envMap ) { + } - needsProgramChange = true; + // - } else if ( material.fog === true && materialProperties.fog !== fog ) { + let program = materialProperties.currentProgram; - needsProgramChange = true; + if ( needsProgramChange === true ) { - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { + program = getProgram( material, scene, object ); - needsProgramChange = true; + } - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { + let refreshProgram = false; + let refreshMaterial = false; + let refreshLights = false; - needsProgramChange = true; + const p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.uniforms; - } else if ( materialProperties.vertexTangents !== vertexTangents ) { + if ( state.useProgram( program.program ) ) { - needsProgramChange = true; + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - } else if ( materialProperties.morphTargets !== morphTargets ) { + } - needsProgramChange = true; + if ( material.id !== _currentMaterialId ) { - } else if ( materialProperties.morphNormals !== morphNormals ) { + _currentMaterialId = material.id; - needsProgramChange = true; + refreshMaterial = true; - } else if ( materialProperties.morphColors !== morphColors ) { + } - needsProgramChange = true; + if ( refreshProgram || _currentCamera !== camera ) { - } else if ( materialProperties.toneMapping !== toneMapping ) { + // common camera uniforms - needsProgramChange = true; + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { + const uCamPos = p_uniforms.map.cameraPosition; - needsProgramChange = true; + if ( uCamPos !== undefined ) { - } + uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - } else { + } - needsProgramChange = true; - materialProperties.__version = material.version; + if ( capabilities.logarithmicDepthBuffer ) { - } + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - // + } - let program = materialProperties.currentProgram; + // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 - if ( needsProgramChange === true ) { + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial ) { - program = getProgram( material, scene, object ); + p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - } + } - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; + if ( _currentCamera !== camera ) { - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; + _currentCamera = camera; - if ( state.useProgram( program.program ) ) { + // lighting uniforms depend on the camera so enforce an update + // now, in case this material supports lights - or later, when + // the next material that does gets activated: - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - } + } - if ( material.id !== _currentMaterialId ) { + } - _currentMaterialId = material.id; + // skinning and morph target uniforms must be set even if material didn't change + // auto-setting of texture unit for bone and morph texture must go before other textures + // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - refreshMaterial = true; + if ( object.isSkinnedMesh ) { - } + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - if ( refreshProgram || _currentCamera !== camera ) { + const skeleton = object.skeleton; - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( skeleton ) { - if ( capabilities.logarithmicDepthBuffer ) { + if ( capabilities.floatVertexTextures ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - } + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - if ( _currentCamera !== camera ) { + } else { - _currentCamera = camera; + console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: + } - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + } } - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + if ( object.isBatchedMesh ) { - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshStandardMaterial || - material.envMap ) { + p_uniforms.setOptional( _gl, object, 'batchingTexture' ); + p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); - const uCamPos = p_uniforms.map.cameraPosition; + } - if ( uCamPos !== undefined ) { + const morphAttributes = geometry.morphAttributes; - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - } + morphtargets.update( object, geometry, program ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { + if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); + materialProperties.receiveShadow = object.receiveShadow; + p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.isShadowMaterial || - object.isSkinnedMesh ) { + // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - } + m_uniforms.envMap.value = envMap; - } + m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures + } - if ( object.isSkinnedMesh ) { + if ( refreshMaterial ) { - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - const skeleton = object.skeleton; + if ( materialProperties.needsLights ) { + + // the current material requires lighting info - if ( skeleton ) { + // note: all lighting uniforms are always set correctly + // they simply reference the renderer's state for their + // values + // + // use the current material's .needsUpdate flags to set + // the GL state when required - if ( capabilities.floatVertexTextures ) { + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); + } - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + // refresh uniforms common to several materials - } else { + if ( fog && material.fog === true ) { - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); + materials.refreshFogUniforms( m_uniforms, fog ); } + materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + } - } + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - const morphAttributes = geometry.morphAttributes; + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + material.uniformsNeedUpdate = false; - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { + } - morphtargets.update( object, geometry, material, program ); + if ( material.isSpriteMaterial ) { - } + p_uniforms.setValue( _gl, 'center', object.center ); - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { + } - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); + // common matrices - } + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 + // UBOs - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { + if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - m_uniforms.envMap.value = envMap; + const groups = material.uniformsGroups; - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + for ( let i = 0, l = groups.length; i < l; i ++ ) { - } + if ( capabilities.isWebGL2 ) { - if ( refreshMaterial ) { + const group = groups[ i ]; - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + uniformsGroups.update( group, program ); + uniformsGroups.bind( group, program ); - if ( materialProperties.needsLights ) { + } else { - // the current material requires lighting info + console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required + } - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + } } - // refresh uniforms common to several materials + return program; - if ( fog && material.fog === true ) { + } - materials.refreshFogUniforms( m_uniforms, fog ); + // If uniforms are marked as clean, they don't need to be loaded to the GPU. - } + function markUniformsLightsNeedsUpdate( uniforms, value ) { - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + uniforms.ambientLightColor.needsUpdate = value; + uniforms.lightProbe.needsUpdate = value; - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + 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; } - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + function materialNeedsLights( material ) { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - material.uniformsNeedUpdate = false; + return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || + material.isMeshStandardMaterial || material.isShadowMaterial || + ( material.isShaderMaterial && material.lights === true ); } - if ( material.isSpriteMaterial ) { + this.getActiveCubeFace = function () { - p_uniforms.setValue( _gl, 'center', object.center ); + return _currentActiveCubeFace; - } + }; + + this.getActiveMipmapLevel = function () { + + return _currentActiveMipmapLevel; - // common matrices + }; - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); + this.getRenderTarget = function () { - // UBOs + return _currentRenderTarget; - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { + }; - const groups = material.uniformsGroups; + this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - for ( let i = 0, l = groups.length; i < l; i ++ ) { + properties.get( renderTarget.texture ).__webglTexture = colorTexture; + properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - if ( capabilities.isWebGL2 ) { + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__hasExternalTextures = true; - const group = groups[ i ]; + if ( renderTargetProperties.__hasExternalTextures ) { - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); + renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; - } else { + if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + + // The multisample_render_to_texture extension doesn't work properly if there + // are midframe flushes and an external depth buffer. Disable use of the extension. + if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); + console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); + renderTargetProperties.__useRenderToTexture = false; + + } } } - } + }; - return program; + this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - } + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__webglFramebuffer = defaultFramebuffer; + renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + }; - function markUniformsLightsNeedsUpdate( uniforms, value ) { + this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; + _currentRenderTarget = renderTarget; + _currentActiveCubeFace = activeCubeFace; + _currentActiveMipmapLevel = activeMipmapLevel; - 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; + let useDefaultFramebuffer = true; + let framebuffer = null; + let isCube = false; + let isRenderTarget3D = false; - } + if ( renderTarget ) { - function materialNeedsLights( material ) { + const renderTargetProperties = properties.get( renderTarget ); - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); + if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - } + // We need to make sure to rebind the framebuffer. + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); + useDefaultFramebuffer = false; - this.getActiveCubeFace = function () { + } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - return _currentActiveCubeFace; + textures.setupRenderTarget( renderTarget ); - }; + } else if ( renderTargetProperties.__hasExternalTextures ) { - this.getActiveMipmapLevel = function () { + // Color and depth texture must be rebound in order for the swapchain to update. + textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - return _currentActiveMipmapLevel; + } - }; + const texture = renderTarget.texture; - this.getRenderTarget = function () { + if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - return _currentRenderTarget; + isRenderTarget3D = true; - }; + } - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { + const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; + if ( renderTarget.isWebGLCubeRenderTarget ) { - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; + if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { - if ( renderTargetProperties.__hasExternalTextures ) { + framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; + } else { - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + framebuffer = __webglFramebuffer[ activeCubeFace ]; - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { + } - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; + isCube = true; - } + } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - } + framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - } + } else { - }; + if ( Array.isArray( __webglFramebuffer ) ) { - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { + framebuffer = __webglFramebuffer[ activeMipmapLevel ]; - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; + } else { - }; + framebuffer = __webglFramebuffer; - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { + } - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; + } - let useDefaultFramebuffer = true; - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - if ( renderTarget ) { + } else { - const renderTargetProperties = properties.get( renderTarget ); + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); + _currentScissorTest = _scissorTest; - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { + } - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( 36160, null ); - useDefaultFramebuffer = false; + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { + if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - textures.setupRenderTarget( renderTarget ); + state.drawBuffers( renderTarget, framebuffer ); - } else if ( renderTargetProperties.__hasExternalTextures ) { + } - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - } + if ( isCube ) { - const texture = renderTarget.texture; + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + } else if ( isRenderTarget3D ) { - isRenderTarget3D = true; + const textureProperties = properties.get( renderTarget.texture ); + const layer = activeCubeFace || 0; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); } - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + + }; + + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - if ( renderTarget.isWebGLCubeRenderTarget ) { + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - framebuffer = __webglFramebuffer[ activeCubeFace ]; - isCube = true; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { + } - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; + let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - } else { + if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - framebuffer = __webglFramebuffer; + framebuffer = framebuffer[ activeCubeFaceIndex ]; } - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + if ( framebuffer ) { - } else { + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; + try { - } + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - state.drawBuffers( renderTarget, framebuffer ); + } - } + const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! halfFloatSupportedByExt ) { - if ( isCube ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); + } - } else if ( isRenderTarget3D ) { + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - } + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + } - }; + } finally { - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { + // restore framebuffer of current render target if necessary - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + } - } + } - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; + }; - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { + this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - framebuffer = framebuffer[ activeCubeFaceIndex ]; + const levelScale = Math.pow( 2, - level ); + const width = Math.floor( texture.image.width * levelScale ); + const height = Math.floor( texture.image.height * levelScale ); - } + textures.setTexture2D( texture, 0 ); - if ( framebuffer ) { + _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); - state.bindFramebuffer( 36160, framebuffer ); + state.unbindTexture(); - try { + }; - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { + const width = srcTexture.image.width; + const height = srcTexture.image.height; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + textures.setTexture2D( dstTexture, 0 ); - } + // As another texture upload may have changed pixelStorei + // parameters, make sure they are correct for the dstTexture + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); + if ( srcTexture.isDataTexture ) { - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + } else { - } + if ( srcTexture.isCompressedTexture ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + } else { - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); } - } finally { - - // restore framebuffer of current render target if necessary + } - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( 36160, framebuffer ); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); - } + state.unbindTexture(); - } + }; - }; + this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { + if ( _this.isWebGL1Renderer ) { - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); + return; - textures.setTexture2D( texture, 0 ); + } - _gl.copyTexSubImage2D( 3553, level, 0, 0, position.x, position.y, width, height ); + const width = sourceBox.max.x - sourceBox.min.x + 1; + const height = sourceBox.max.y - sourceBox.min.y + 1; + const depth = sourceBox.max.z - sourceBox.min.z + 1; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); + let glTarget; - state.unbindTexture(); + if ( dstTexture.isData3DTexture ) { - }; + textures.setTexture3D( dstTexture, 0 ); + glTarget = _gl.TEXTURE_3D; - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { + } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); + textures.setTexture2DArray( dstTexture, 0 ); + glTarget = _gl.TEXTURE_2D_ARRAY; - textures.setTexture2D( dstTexture, 0 ); + } else { - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); + return; - if ( srcTexture.isDataTexture ) { + } - _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - } else { + const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); + const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); + const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); + const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); + const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); - if ( srcTexture.isCompressedTexture ) { + const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; - _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); - } else { + if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - } + } else { - } + if ( srcTexture.isCompressedArrayTexture ) { - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); + _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - state.unbindTexture(); + } else { - }; + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { + } - if ( _this.isWebGL1Renderer ) { + } - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); - } + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; + state.unbindTexture(); - if ( dstTexture.isData3DTexture ) { + }; - textures.setTexture3D( dstTexture, 0 ); - glTarget = 32879; + this.initTexture = function ( texture ) { - } else if ( dstTexture.isDataArrayTexture ) { + if ( texture.isCubeTexture ) { - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = 35866; + textures.setTextureCube( texture, 0 ); - } else { + } else if ( texture.isData3DTexture ) { - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; + textures.setTexture3D( texture, 0 ); - } + } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + textures.setTexture2DArray( texture, 0 ); - const unpackRowLen = _gl.getParameter( 3314 ); - const unpackImageHeight = _gl.getParameter( 32878 ); - const unpackSkipPixels = _gl.getParameter( 3316 ); - const unpackSkipRows = _gl.getParameter( 3315 ); - const unpackSkipImages = _gl.getParameter( 32877 ); + } else { - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; + textures.setTexture2D( texture, 0 ); - _gl.pixelStorei( 3314, image.width ); - _gl.pixelStorei( 32878, image.height ); - _gl.pixelStorei( 3316, sourceBox.min.x ); - _gl.pixelStorei( 3315, sourceBox.min.y ); - _gl.pixelStorei( 32877, sourceBox.min.z ); + } - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { + state.unbindTexture(); - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); + }; - } else { + this.resetState = function () { - if ( srcTexture.isCompressedArrayTexture ) { + _currentActiveCubeFace = 0; + _currentActiveMipmapLevel = 0; + _currentRenderTarget = null; - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); + state.reset(); + bindingStates.reset(); - } else { + }; - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - } + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); } - _gl.pixelStorei( 3314, unpackRowLen ); - _gl.pixelStorei( 32878, unpackImageHeight ); - _gl.pixelStorei( 3316, unpackSkipPixels ); - _gl.pixelStorei( 3315, unpackSkipRows ); - _gl.pixelStorei( 32877, unpackSkipImages ); + } - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); + get coordinateSystem() { - state.unbindTexture(); + return WebGLCoordinateSystem; - }; + } - this.initTexture = function ( texture ) { + get outputColorSpace() { - if ( texture.isCubeTexture ) { + return this._outputColorSpace; - textures.setTextureCube( texture, 0 ); + } - } else if ( texture.isData3DTexture ) { + set outputColorSpace( colorSpace ) { - textures.setTexture3D( texture, 0 ); + this._outputColorSpace = colorSpace; - } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + const gl = this.getContext(); + gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; + gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; - textures.setTexture2DArray( texture, 0 ); + } - } else { + get outputEncoding() { // @deprecated, r152 - textures.setTexture2D( texture, 0 ); + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; - } + } - state.unbindTexture(); + set outputEncoding( encoding ) { // @deprecated, r152 - }; + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; - this.resetState = function () { + } - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; + get useLegacyLights() { // @deprecated, r155 - state.reset(); - bindingStates.reset(); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + return this._useLegacyLights; - }; + } - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + set useLegacyLights( value ) { // @deprecated, r155 - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + this._useLegacyLights = value; } @@ -28722,29 +30488,13 @@ const data = super.toJSON( meta ); if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - if ( this.backgroundBlurriness > 0 ) data.backgroundBlurriness = this.backgroundBlurriness; - if ( this.backgroundIntensity !== 1 ) data.backgroundIntensity = this.backgroundIntensity; + if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; + if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; return data; } - // @deprecated - - get autoUpdate() { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - return this.matrixWorldAutoUpdate; - - } - - set autoUpdate( value ) { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - this.matrixWorldAutoUpdate = value; - - } - } class MeshPhongMaterial extends Material { @@ -29077,7 +30827,7 @@ this.type = 'DirectionalLight'; - this.position.copy( Object3D.DefaultUp ); + this.position.copy( Object3D.DEFAULT_UP ); this.updateMatrix(); this.target = new Object3D(); @@ -29232,6 +30982,7 @@ * The azimuthal angle (theta) is measured from the positive z-axis. */ + class Spherical { constructor( radius = 1, phi = 0, theta = 0 ) { @@ -29330,7 +31081,7 @@ } - // This set of controls performs orbiting, dollying (zooming), and panning. + // OrbitControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). // // Orbit - left mouse / touch: one-finger move @@ -29340,6 +31091,9 @@ const _changeEvent = { type: 'change' }; const _startEvent = { type: 'start' }; const _endEvent = { type: 'end' }; + const _ray = new Ray(); + const _plane = new Plane(); + const TILT_LIMIT = Math.cos( 70 * MathUtils.DEG2RAD ); class OrbitControls extends EventDispatcher { @@ -29357,6 +31111,9 @@ // "target" sets the location of focus, where the object orbits around this.target = new Vector3(); + // Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect + this.cursor = new Vector3(); + // How far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; this.maxDistance = Infinity; @@ -29365,6 +31122,10 @@ this.minZoom = 0; this.maxZoom = Infinity; + // Limit camera target within a spherical area around the cursor + this.minTargetRadius = 0; + this.maxTargetRadius = Infinity; + // How far you can orbit vertically, upper and lower limits. // Range is 0 to Math.PI radians. this.minPolarAngle = 0; // radians @@ -29394,6 +31155,7 @@ this.panSpeed = 1.0; this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up this.keyPanSpeed = 7.0; // pixels moved per arrow key push + this.zoomToCursor = false; // Set to true to automatically rotate around the target // If auto-rotate is enabled, you must call controls.update() in your animation loop @@ -29446,6 +31208,13 @@ }; + this.stopListenToKeyEvents = function () { + + this._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + this._domElementKeyEvents = null; + + }; + this.saveState = function () { scope.target0.copy( scope.target ); @@ -29480,10 +31249,11 @@ const lastPosition = new Vector3(); const lastQuaternion = new Quaternion(); + const lastTargetPosition = new Vector3(); const twoPI = 2 * Math.PI; - return function update() { + return function update( deltaTime = null ) { const position = scope.object.position; @@ -29497,7 +31267,7 @@ if ( scope.autoRotate && state === STATE.NONE ) { - rotateLeft( getAutoRotationAngle() ); + rotateLeft( getAutoRotationAngle( deltaTime ) ); } @@ -29544,11 +31314,6 @@ spherical.makeSafe(); - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - // move target to panned location if ( scope.enableDamping === true ) { @@ -29561,6 +31326,23 @@ } + // Limit the target distance from the cursor to create a sphere around the center of interest + scope.target.sub( scope.cursor ); + scope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius ); + scope.target.add( scope.cursor ); + + // adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera + // we adjust zoom later in these cases + if ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) { + + spherical.radius = clampDistance( spherical.radius ); + + } else { + + spherical.radius = clampDistance( spherical.radius * scale ); + + } + offset.setFromSpherical( spherical ); // rotate offset back to "camera-up-vector-is-up" space @@ -29585,7 +31367,91 @@ } + // adjust camera position + let zoomChanged = false; + if ( scope.zoomToCursor && performCursorZoom ) { + + let newRadius = null; + if ( scope.object.isPerspectiveCamera ) { + + // move the camera down the pointer ray + // this method avoids floating point error + const prevRadius = offset.length(); + newRadius = clampDistance( prevRadius * scale ); + + const radiusDelta = prevRadius - newRadius; + scope.object.position.addScaledVector( dollyDirection, radiusDelta ); + scope.object.updateMatrixWorld(); + + } else if ( scope.object.isOrthographicCamera ) { + + // adjust the ortho camera position based on zoom changes + const mouseBefore = new Vector3( mouse.x, mouse.y, 0 ); + mouseBefore.unproject( scope.object ); + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + const mouseAfter = new Vector3( mouse.x, mouse.y, 0 ); + mouseAfter.unproject( scope.object ); + + scope.object.position.sub( mouseAfter ).add( mouseBefore ); + scope.object.updateMatrixWorld(); + + newRadius = offset.length(); + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' ); + scope.zoomToCursor = false; + + } + + // handle the placement of the target + if ( newRadius !== null ) { + + if ( this.screenSpacePanning ) { + + // position the orbit target in front of the new camera position + scope.target.set( 0, 0, - 1 ) + .transformDirection( scope.object.matrix ) + .multiplyScalar( newRadius ) + .add( scope.object.position ); + + } else { + + // get the ray and translation plane to compute target + _ray.origin.copy( scope.object.position ); + _ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix ); + + // if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid + // extremely large values + if ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) { + + object.lookAt( scope.target ); + + } else { + + _plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target ); + _ray.intersectPlane( _plane, scope.target ); + + } + + } + + } + + } else if ( scope.object.isOrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } + scale = 1; + performCursorZoom = false; // update condition is: // min(camera displacement, camera rotation in radians)^2 > EPS @@ -29593,13 +31459,14 @@ if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS || + lastTargetPosition.distanceToSquared( scope.target ) > 0 ) { scope.dispatchEvent( _changeEvent ); lastPosition.copy( scope.object.position ); lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; + lastTargetPosition.copy( scope.target ); return true; @@ -29616,7 +31483,7 @@ scope.domElement.removeEventListener( 'contextmenu', onContextMenu ); scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); - scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.removeEventListener( 'pointercancel', onPointerUp ); scope.domElement.removeEventListener( 'wheel', onMouseWheel ); scope.domElement.removeEventListener( 'pointermove', onPointerMove ); @@ -29626,6 +31493,7 @@ if ( scope._domElementKeyEvents !== null ) { scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + scope._domElementKeyEvents = null; } @@ -29660,7 +31528,6 @@ let scale = 1; const panOffset = new Vector3(); - let zoomChanged = false; const rotateStart = new Vector2(); const rotateEnd = new Vector2(); @@ -29674,18 +31541,31 @@ const dollyEnd = new Vector2(); const dollyDelta = new Vector2(); + const dollyDirection = new Vector3(); + const mouse = new Vector2(); + let performCursorZoom = false; + const pointers = []; const pointerPositions = {}; - function getAutoRotationAngle() { + function getAutoRotationAngle( deltaTime ) { + + if ( deltaTime !== null ) { + + return ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime; - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + } else { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } } - function getZoomScale() { + function getZoomScale( delta ) { - return Math.pow( 0.95, scope.zoomSpeed ); + const normalized_delta = Math.abs( delta ) / ( 100 * ( window.devicePixelRatio | 0 ) ); + return Math.pow( 0.95, scope.zoomSpeed * normalized_delta ); } @@ -29784,16 +31664,10 @@ function dollyOut( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale /= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -29805,16 +31679,10 @@ function dollyIn( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale *= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -29824,6 +31692,35 @@ } + function updateZoomParameters( x, y ) { + + if ( ! scope.zoomToCursor ) { + + return; + + } + + performCursorZoom = true; + + const rect = scope.domElement.getBoundingClientRect(); + const dx = x - rect.left; + const dy = y - rect.top; + const w = rect.width; + const h = rect.height; + + mouse.x = ( dx / w ) * 2 - 1; + mouse.y = - ( dy / h ) * 2 + 1; + + dollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize(); + + } + + function clampDistance( dist ) { + + return Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) ); + + } + // // event callbacks - update the object state // @@ -29836,6 +31733,7 @@ function handleMouseDownDolly( event ) { + updateZoomParameters( event.clientX, event.clientX ); dollyStart.set( event.clientX, event.clientY ); } @@ -29872,11 +31770,11 @@ if ( dollyDelta.y > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( dollyDelta.y ) ); } else if ( dollyDelta.y < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( dollyDelta.y ) ); } @@ -29902,13 +31800,15 @@ function handleMouseWheel( event ) { + updateZoomParameters( event.clientX, event.clientY ); + if ( event.deltaY < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( event.deltaY ) ); } else if ( event.deltaY > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( event.deltaY ) ); } @@ -29996,16 +31896,18 @@ } - function handleTouchStartRotate() { + function handleTouchStartRotate( event ) { if ( pointers.length === 1 ) { - rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + rotateStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); rotateStart.set( x, y ); @@ -30013,16 +31915,18 @@ } - function handleTouchStartPan() { + function handleTouchStartPan( event ) { if ( pointers.length === 1 ) { - panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + panStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); panStart.set( x, y ); @@ -30030,10 +31934,12 @@ } - function handleTouchStartDolly() { + function handleTouchStartDolly( event ) { + + const position = getSecondPointerPosition( event ); - const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX; - const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY; + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; const distance = Math.sqrt( dx * dx + dy * dy ); @@ -30041,19 +31947,19 @@ } - function handleTouchStartDollyPan() { + function handleTouchStartDollyPan( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enablePan ) handleTouchStartPan(); + if ( scope.enablePan ) handleTouchStartPan( event ); } - function handleTouchStartDollyRotate() { + function handleTouchStartDollyRotate( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enableRotate ) handleTouchStartRotate(); + if ( scope.enableRotate ) handleTouchStartRotate( event ); } @@ -30128,6 +32034,11 @@ dollyStart.copy( dollyEnd ); + const centerX = ( event.pageX + position.x ) * 0.5; + const centerY = ( event.pageY + position.y ) * 0.5; + + updateZoomParameters( centerX, centerY ); + } function handleTouchMoveDollyPan( event ) { @@ -30197,26 +32108,20 @@ function onPointerUp( event ) { - removePointer( event ); - - if ( pointers.length === 0 ) { - - scope.domElement.releasePointerCapture( event.pointerId ); - - scope.domElement.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.removeEventListener( 'pointerup', onPointerUp ); + removePointer( event ); - } + if ( pointers.length === 0 ) { - scope.dispatchEvent( _endEvent ); + scope.domElement.releasePointerCapture( event.pointerId ); - state = STATE.NONE; + scope.domElement.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.removeEventListener( 'pointerup', onPointerUp ); - } + } - function onPointerCancel( event ) { + scope.dispatchEvent( _endEvent ); - removePointer( event ); + state = STATE.NONE; } @@ -30385,7 +32290,7 @@ if ( scope.enableRotate === false ) return; - handleTouchStartRotate(); + handleTouchStartRotate( event ); state = STATE.TOUCH_ROTATE; @@ -30395,7 +32300,7 @@ if ( scope.enablePan === false ) return; - handleTouchStartPan(); + handleTouchStartPan( event ); state = STATE.TOUCH_PAN; @@ -30417,7 +32322,7 @@ if ( scope.enableZoom === false && scope.enablePan === false ) return; - handleTouchStartDollyPan(); + handleTouchStartDollyPan( event ); state = STATE.TOUCH_DOLLY_PAN; @@ -30427,7 +32332,7 @@ if ( scope.enableZoom === false && scope.enableRotate === false ) return; - handleTouchStartDollyRotate(); + handleTouchStartDollyRotate( event ); state = STATE.TOUCH_DOLLY_ROTATE; @@ -30519,7 +32424,7 @@ function addPointer( event ) { - pointers.push( event ); + pointers.push( event.pointerId ); } @@ -30529,7 +32434,7 @@ for ( let i = 0; i < pointers.length; i ++ ) { - if ( pointers[ i ].pointerId == event.pointerId ) { + if ( pointers[ i ] == event.pointerId ) { pointers.splice( i, 1 ); return; @@ -30557,9 +32462,9 @@ function getSecondPointerPosition( event ) { - const pointer = ( event.pointerId === pointers[ 0 ].pointerId ) ? pointers[ 1 ] : pointers[ 0 ]; + const pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ]; - return pointerPositions[ pointer.pointerId ]; + return pointerPositions[ pointerId ]; } @@ -30568,7 +32473,7 @@ scope.domElement.addEventListener( 'contextmenu', onContextMenu ); scope.domElement.addEventListener( 'pointerdown', onPointerDown ); - scope.domElement.addEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.addEventListener( 'pointercancel', onPointerUp ); scope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } ); // force an update at start @@ -30579,10 +32484,8 @@ } - - // This set of controls performs orbiting, dollying (zooming), and panning. + // MapControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). - // This is very similar to OrbitControls, another set of touch behavior // // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish @@ -30596,11 +32499,9 @@ this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up - this.mouseButtons.LEFT = MOUSE.PAN; - this.mouseButtons.RIGHT = MOUSE.ROTATE; + this.mouseButtons = { LEFT: MOUSE.PAN, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.ROTATE }; - this.touches.ONE = TOUCH.PAN; - this.touches.TWO = TOUCH.DOLLY_ROTATE; + this.touches = { ONE: TOUCH.PAN, TWO: TOUCH.DOLLY_ROTATE }; } @@ -30627,10 +32528,10 @@ const shader = Sky.SkyShader; const material = new ShaderMaterial( { - name: 'SkyShader', - fragmentShader: shader.fragmentShader, - vertexShader: shader.vertexShader, + name: shader.name, uniforms: UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, side: BackSide, depthWrite: false } ); @@ -30645,6 +32546,8 @@ Sky.SkyShader = { + name: 'SkyShader', + uniforms: { 'turbidity': { value: 2 }, 'rayleigh': { value: 1 }, @@ -30737,8 +32640,6 @@ uniform float mieDirectionalG; uniform vec3 up; - const vec3 cameraPos = vec3( 0.0, 0.0, 0.0 ); - // constants for atmospheric scattering const float pi = 3.141592653589793238462643383279502884197169; @@ -30768,7 +32669,7 @@ void main() { - vec3 direction = normalize( vWorldPosition - cameraPos ); + vec3 direction = normalize( vWorldPosition - cameraPosition ); // optical length // cutoff angle at 90 to avoid singularity in next formula. @@ -30809,7 +32710,7 @@ gl_FragColor = vec4( retColor, 1.0 ); #include - #include + #include }` @@ -32118,7 +34019,7 @@ class MapView extends Mesh { constructor(root = MapView.PLANAR, provider = new OpenStreetMapsProvider(), heightProvider = null) { - super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0 })); + super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0, depthWrite: false, colorWrite: false })); this.lod = null; this.provider = null; this.heightProvider = null; diff --git a/examples/transition.js b/examples/transition.js index 100fc48..88faa36 100644 --- a/examples/transition.js +++ b/examples/transition.js @@ -3,10 +3,11 @@ /** * @license - * Copyright 2010-2022 Three.js Authors + * Copyright 2010-2023 Three.js Authors * SPDX-License-Identifier: MIT */ - const REVISION = '147'; + const REVISION = '160'; + const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 }; const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 }; const CullFaceNone = 0; @@ -40,6 +41,10 @@ const DstColorFactor = 208; const OneMinusDstColorFactor = 209; const SrcAlphaSaturateFactor = 210; + const ConstantColorFactor = 211; + const OneMinusConstantColorFactor = 212; + const ConstantAlphaFactor = 213; + const OneMinusConstantAlphaFactor = 214; const NeverDepth = 0; const AlwaysDepth = 1; const LessDepth = 2; @@ -57,6 +62,7 @@ const CineonToneMapping = 3; const ACESFilmicToneMapping = 4; const CustomToneMapping = 5; + const AgXToneMapping = 6; const UVMapping = 300; const CubeReflectionMapping = 301; @@ -85,7 +91,6 @@ const UnsignedShort5551Type = 1018; const UnsignedInt248Type = 1020; const AlphaFormat = 1021; - const RGBFormat = 1022; // @deprecated since r137 const RGBAFormat = 1023; const LuminanceFormat = 1024; const LuminanceAlphaFormat = 1025; @@ -123,22 +128,53 @@ const RGBA_ASTC_12x10_Format = 37820; const RGBA_ASTC_12x12_Format = 37821; const RGBA_BPTC_Format = 36492; + const RGB_BPTC_SIGNED_Format = 36494; + const RGB_BPTC_UNSIGNED_Format = 36495; + const RED_RGTC1_Format = 36283; + const SIGNED_RED_RGTC1_Format = 36284; + const RED_GREEN_RGTC2_Format = 36285; + const SIGNED_RED_GREEN_RGTC2_Format = 36286; + /** @deprecated Use LinearSRGBColorSpace or NoColorSpace in three.js r152+. */ const LinearEncoding = 3000; + /** @deprecated Use SRGBColorSpace in three.js r152+. */ const sRGBEncoding = 3001; const BasicDepthPacking = 3200; const RGBADepthPacking = 3201; const TangentSpaceNormalMap = 0; const ObjectSpaceNormalMap = 1; + + // Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available. + const NoColorSpace = ''; const SRGBColorSpace = 'srgb'; const LinearSRGBColorSpace = 'srgb-linear'; + const DisplayP3ColorSpace = 'display-p3'; + const LinearDisplayP3ColorSpace = 'display-p3-linear'; + + const LinearTransfer = 'linear'; + const SRGBTransfer = 'srgb'; + + const Rec709Primaries = 'rec709'; + const P3Primaries = 'p3'; const KeepStencilOp = 7680; const AlwaysStencilFunc = 519; + const NeverCompare = 512; + const LessCompare = 513; + const EqualCompare = 514; + const LessEqualCompare = 515; + const GreaterCompare = 516; + const NotEqualCompare = 517; + const GreaterEqualCompare = 518; + const AlwaysCompare = 519; + const StaticDrawUsage = 35044; const GLSL3 = '300 es'; const _SRGBAFormat = 1035; // fallback for WebGL 1 + const WebGLCoordinateSystem = 2000; + const WebGPUCoordinateSystem = 2001; + /** * https://github.com/mrdoob/eventdispatcher.js/ */ @@ -226,6 +262,8 @@ 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' ]; + let _seed = 1234567; + const DEG2RAD = Math.PI / 180; const RAD2DEG = 180 / Math.PI; @@ -261,6 +299,28 @@ } + // Linear mapping from range to range + function mapLinear( x, a1, a2, b1, b2 ) { + + 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 ) { @@ -268,18 +328,167 @@ } + // http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/ + function damp( x, y, lambda, dt ) { + + return lerp( x, y, 1 - Math.exp( - lambda * dt ) ); + + } + + // https://www.desmos.com/calculator/vcsjnyz7x4 + function pingpong( x, length = 1 ) { + + return length - Math.abs( euclideanModulo( x, length * 2 ) - length ); + + } + + // http://en.wikipedia.org/wiki/Smoothstep + function smoothstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * ( 3 - 2 * x ); + + } + + function smootherstep( x, min, max ) { + + if ( x <= min ) return 0; + if ( x >= max ) return 1; + + x = ( x - min ) / ( max - min ); + + return x * x * x * ( x * ( x * 6 - 15 ) + 10 ); + + } + + // Random integer from interval + function randInt( low, high ) { + + return low + Math.floor( Math.random() * ( high - low + 1 ) ); + + } + + // Random float from interval + function randFloat( low, high ) { + + return low + Math.random() * ( high - low ); + + } + + // Random float from <-range/2, range/2> interval + function randFloatSpread( range ) { + + return range * ( 0.5 - Math.random() ); + + } + + // Deterministic pseudo-random float in the interval [ 0, 1 ] + function seededRandom( s ) { + + if ( s !== undefined ) _seed = s; + + // Mulberry32 generator + + let t = _seed += 0x6D2B79F5; + + t = Math.imul( t ^ t >>> 15, t | 1 ); + + t ^= t + Math.imul( t ^ t >>> 7, t | 61 ); + + return ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296; + + } + + function degToRad( degrees ) { + + return degrees * DEG2RAD; + + } + + function radToDeg( radians ) { + + return radians * RAD2DEG; + + } + function isPowerOfTwo( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } + function ceilPowerOfTwo( value ) { + + return Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) ); + + } + function floorPowerOfTwo( value ) { return Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) ); } + function setQuaternionFromProperEuler( q, a, b, c, order ) { + + // Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles + + // rotations are applied to the axes in the order specified by 'order' + // rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c' + // angles are in radians + + const cos = Math.cos; + const sin = Math.sin; + + const c2 = cos( b / 2 ); + const s2 = sin( b / 2 ); + + const c13 = cos( ( a + c ) / 2 ); + const s13 = sin( ( a + c ) / 2 ); + + const c1_3 = cos( ( a - c ) / 2 ); + const s1_3 = sin( ( a - c ) / 2 ); + + const c3_1 = cos( ( c - a ) / 2 ); + const s3_1 = sin( ( c - a ) / 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 ); + + } + + } + function denormalize( value, array ) { switch ( array.constructor ) { @@ -288,6 +497,10 @@ return value; + case Uint32Array: + + return value / 4294967295.0; + case Uint16Array: return value / 65535.0; @@ -296,6 +509,10 @@ return value / 255.0; + case Int32Array: + + return Math.max( value / 2147483647.0, - 1.0 ); + case Int16Array: return Math.max( value / 32767.0, - 1.0 ); @@ -320,6 +537,10 @@ return value; + case Uint32Array: + + return Math.round( value * 4294967295.0 ); + case Uint16Array: return Math.round( value * 65535.0 ); @@ -328,6 +549,10 @@ return Math.round( value * 255.0 ); + case Int32Array: + + return Math.round( value * 2147483647.0 ); + case Int16Array: return Math.round( value * 32767.0 ); @@ -344,6 +569,33 @@ } + 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 ) { @@ -637,8 +889,8 @@ roundToZero() { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); return this; @@ -699,6 +951,20 @@ } + angleTo( v ) { + + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + + if ( denominator === 0 ) return Math.PI / 2; + + const theta = this.dot( v ) / denominator; + + // clamp, to handle numerical problems + + return Math.acos( clamp( theta, - 1, 1 ) ); + + } + distanceTo( v ) { return Math.sqrt( this.distanceToSquared( v ) ); @@ -809,7 +1075,7 @@ class Matrix3 { - constructor() { + constructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { Matrix3.prototype.isMatrix3 = true; @@ -821,6 +1087,12 @@ ]; + if ( n11 !== undefined ) { + + this.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ); + + } + } set( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { @@ -1070,13 +1342,27 @@ makeTranslation( x, y ) { - this.set( + if ( x.isVector2 ) { - 1, 0, x, - 0, 1, y, - 0, 0, 1 + 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; @@ -1194,3538 +1480,3548 @@ } - function SRGBToLinear( c ) { + function createCanvasElement() { - return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); + const canvas = createElementNS( 'canvas' ); + canvas.style.display = 'block'; + return canvas; } - function LinearToSRGB( c ) { + const _cache = {}; - return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; + function warnOnce( message ) { + + if ( message in _cache ) return; + + _cache[ message ] = true; + + console.warn( message ); } - // JavaScript RGB-to-RGB transforms, defined as - // FN[InputColorSpace][OutputColorSpace] callback functions. - const FN = { - [ SRGBColorSpace ]: { [ LinearSRGBColorSpace ]: SRGBToLinear }, - [ LinearSRGBColorSpace ]: { [ SRGBColorSpace ]: LinearToSRGB }, + /** + * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping + * or clipping. Based on W3C specifications for sRGB and Display P3, + * and ICC specifications for the D50 connection space. Values in/out + * are _linear_ sRGB and _linear_ Display P3. + * + * Note that both sRGB and Display P3 use the sRGB transfer functions. + * + * Reference: + * - http://www.russellcottrell.com/photo/matrixCalculator.htm + */ + + const LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set( + 0.8224621, 0.177538, 0.0, + 0.0331941, 0.9668058, 0.0, + 0.0170827, 0.0723974, 0.9105199, + ); + + const LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set( + 1.2249401, - 0.2249404, 0.0, + - 0.0420569, 1.0420571, 0.0, + - 0.0196376, - 0.0786361, 1.0982735 + ); + + /** + * Defines supported color spaces by transfer function and primaries, + * and provides conversions to/from the Linear-sRGB reference space. + */ + const COLOR_SPACES = { + [ LinearSRGBColorSpace ]: { + transfer: LinearTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color, + fromReference: ( color ) => color, + }, + [ SRGBColorSpace ]: { + transfer: SRGBTransfer, + primaries: Rec709Primaries, + toReference: ( color ) => color.convertSRGBToLinear(), + fromReference: ( color ) => color.convertLinearToSRGB(), + }, + [ LinearDisplayP3ColorSpace ]: { + transfer: LinearTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ), + }, + [ DisplayP3ColorSpace ]: { + transfer: SRGBTransfer, + primaries: P3Primaries, + toReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ), + fromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(), + }, }; + const SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] ); + const ColorManagement = { - legacyMode: true, + enabled: true, + + _workingColorSpace: LinearSRGBColorSpace, get workingColorSpace() { - return LinearSRGBColorSpace; + return this._workingColorSpace; }, set workingColorSpace( colorSpace ) { - console.warn( 'THREE.ColorManagement: .workingColorSpace is readonly.' ); + if ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) { + + throw new Error( `Unsupported working color space, "${ colorSpace }".` ); + + } + + this._workingColorSpace = colorSpace; }, convert: function ( color, sourceColorSpace, targetColorSpace ) { - if ( this.legacyMode || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { + if ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) { return color; } - if ( FN[ sourceColorSpace ] && FN[ sourceColorSpace ][ targetColorSpace ] !== undefined ) { + const sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference; + const targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference; - const fn = FN[ sourceColorSpace ][ targetColorSpace ]; + return targetFromReference( sourceToReference( color ) ); - color.r = fn( color.r ); - color.g = fn( color.g ); - color.b = fn( color.b ); + }, - return color; + fromWorkingColorSpace: function ( color, targetColorSpace ) { - } + return this.convert( color, this._workingColorSpace, targetColorSpace ); + + }, - throw new Error( 'Unsupported color space conversion.' ); + toWorkingColorSpace: function ( color, sourceColorSpace ) { + + return this.convert( color, sourceColorSpace, this._workingColorSpace ); }, - fromWorkingColorSpace: function ( color, targetColorSpace ) { + getPrimaries: function ( colorSpace ) { - return this.convert( color, this.workingColorSpace, targetColorSpace ); + return COLOR_SPACES[ colorSpace ].primaries; }, - toWorkingColorSpace: function ( color, sourceColorSpace ) { + getTransfer: function ( colorSpace ) { - return this.convert( color, sourceColorSpace, this.workingColorSpace ); + if ( colorSpace === NoColorSpace ) return LinearTransfer; + + return COLOR_SPACES[ colorSpace ].transfer; }, }; - const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, - 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, - 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, - 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, - 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, - 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, - 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, - 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, - 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, - 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, - 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, - 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, - 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, - 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, - 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, - 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, - 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, - 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, - 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, - 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, - 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, - 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, - 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, - 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - - const _rgb$1 = { r: 0, g: 0, b: 0 }; - const _hslA = { h: 0, s: 0, l: 0 }; - const _hslB = { h: 0, s: 0, l: 0 }; - function hue2rgb( p, q, t ) { + function SRGBToLinear( c ) { - if ( t < 0 ) t += 1; - if ( t > 1 ) t -= 1; - if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; - if ( t < 1 / 2 ) return q; - if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); - return p; + return ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 ); } - function toComponents( source, target ) { - - target.r = source.r; - target.g = source.g; - target.b = source.b; + function LinearToSRGB( c ) { - return target; + return ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055; } - class Color { - - constructor( r, g, b ) { + let _canvas; - this.isColor = true; + class ImageUtils { - this.r = 1; - this.g = 1; - this.b = 1; + static getDataURL( image ) { - if ( g === undefined && b === undefined ) { + if ( /^data:/i.test( image.src ) ) { - // r is THREE.Color, hex or string - return this.set( r ); + return image.src; } - return this.setRGB( r, g, b ); + if ( typeof HTMLCanvasElement === 'undefined' ) { - } + return image.src; - set( value ) { + } - if ( value && value.isColor ) { + let canvas; - this.copy( value ); + if ( image instanceof HTMLCanvasElement ) { - } else if ( typeof value === 'number' ) { + canvas = image; - this.setHex( value ); + } else { - } else if ( typeof value === 'string' ) { + if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); - this.setStyle( value ); + _canvas.width = image.width; + _canvas.height = image.height; - } + const context = _canvas.getContext( '2d' ); - return this; + if ( image instanceof ImageData ) { - } + context.putImageData( image, 0, 0 ); - setScalar( scalar ) { + } else { - this.r = scalar; - this.g = scalar; - this.b = scalar; + context.drawImage( image, 0, 0, image.width, image.height ); - return this; + } - } + canvas = _canvas; - setHex( hex, colorSpace = SRGBColorSpace ) { + } - hex = Math.floor( hex ); + if ( canvas.width > 2048 || canvas.height > 2048 ) { - this.r = ( hex >> 16 & 255 ) / 255; - this.g = ( hex >> 8 & 255 ) / 255; - this.b = ( hex & 255 ) / 255; + console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); - ColorManagement.toWorkingColorSpace( this, colorSpace ); + return canvas.toDataURL( 'image/jpeg', 0.6 ); - return this; + } else { - } + return canvas.toDataURL( 'image/png' ); - setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { + } - this.r = r; - this.g = g; - this.b = b; + } - ColorManagement.toWorkingColorSpace( this, colorSpace ); + static sRGBToLinear( image ) { - return this; + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - } + const canvas = createElementNS( 'canvas' ); - setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { + canvas.width = image.width; + canvas.height = image.height; - // h,s,l ranges are in 0.0 - 1.0 - h = euclideanModulo( h, 1 ); - s = clamp( s, 0, 1 ); - l = clamp( l, 0, 1 ); + const context = canvas.getContext( '2d' ); + context.drawImage( image, 0, 0, image.width, image.height ); - if ( s === 0 ) { + const imageData = context.getImageData( 0, 0, image.width, image.height ); + const data = imageData.data; - this.r = this.g = this.b = l; + for ( let i = 0; i < data.length; i ++ ) { - } else { + data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; - const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); - const q = ( 2 * l ) - p; + } - this.r = hue2rgb( q, p, h + 1 / 3 ); - this.g = hue2rgb( q, p, h ); - this.b = hue2rgb( q, p, h - 1 / 3 ); + context.putImageData( imageData, 0, 0 ); - } + return canvas; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + } else if ( image.data ) { - return this; + const data = image.data.slice( 0 ); - } + for ( let i = 0; i < data.length; i ++ ) { - setStyle( style, colorSpace = SRGBColorSpace ) { + if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { - function handleAlpha( string ) { + data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); - if ( string === undefined ) return; + } else { - if ( parseFloat( string ) < 1 ) { + // assuming float - console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); + data[ i ] = SRGBToLinear( data[ i ] ); + + } } - } + return { + data: data, + width: image.width, + height: image.height + }; + } else { - let m; + console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); + return image; - if ( m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec( style ) ) { + } - // rgb / hsl + } - let color; - const name = m[ 1 ]; - const components = m[ 2 ]; + } - switch ( name ) { + let _sourceId = 0; - case 'rgb': - case 'rgba': + class Source { - if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { + constructor( data = null ) { - // rgb(255,0,0) rgba(255,0,0,0.5) - this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; - this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; - this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; + this.isSource = true; - ColorManagement.toWorkingColorSpace( this, colorSpace ); + Object.defineProperty( this, 'id', { value: _sourceId ++ } ); - handleAlpha( color[ 4 ] ); + this.uuid = generateUUID(); - return this; + this.data = data; - } + this.version = 0; - 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) - this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; - this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; - this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; + set needsUpdate( value ) { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + if ( value === true ) this.version ++; - handleAlpha( color[ 4 ] ); + } - return this; + toJSON( meta ) { - } + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - break; + if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { - case 'hsl': - case 'hsla': + return meta.images[ this.uuid ]; - 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) - const h = parseFloat( color[ 1 ] ) / 360; - const s = parseFloat( color[ 2 ] ) / 100; - const l = parseFloat( color[ 3 ] ) / 100; + const output = { + uuid: this.uuid, + url: '' + }; - handleAlpha( color[ 4 ] ); + const data = this.data; - return this.setHSL( h, s, l, colorSpace ); + if ( data !== null ) { - } + let url; - break; + if ( Array.isArray( data ) ) { - } + // cube texture - } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { + url = []; - // hex color + for ( let i = 0, l = data.length; i < l; i ++ ) { - const hex = m[ 1 ]; - const size = hex.length; + if ( data[ i ].isDataTexture ) { - if ( size === 3 ) { + url.push( serializeImage( data[ i ].image ) ); - // #ff0 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + url.push( serializeImage( data[ i ] ) ); - return this; + } - } else if ( size === 6 ) { + } - // #ff0000 - this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255; - this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255; - this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255; + } else { - ColorManagement.toWorkingColorSpace( this, colorSpace ); + // texture - return this; + url = serializeImage( data ); } + output.url = url; + } - if ( style && style.length > 0 ) { + if ( ! isRootObject ) { - return this.setColorName( style, colorSpace ); + meta.images[ this.uuid ] = output; } - return this; + return output; } - setColorName( style, colorSpace = SRGBColorSpace ) { + } - // color keywords - const hex = _colorKeywords[ style.toLowerCase() ]; + function serializeImage( image ) { - if ( hex !== undefined ) { + if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || + ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || + ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { - // red - this.setHex( hex, colorSpace ); + // default images - } else { + return ImageUtils.getDataURL( image ); - // unknown color - console.warn( 'THREE.Color: Unknown color ' + style ); + } else { - } + if ( image.data ) { - return this; + // images of DataTexture - } + return { + data: Array.from( image.data ), + width: image.width, + height: image.height, + type: image.data.constructor.name + }; - clone() { + } else { - return new this.constructor( this.r, this.g, this.b ); + console.warn( 'THREE.Texture: Unable to serialize Texture.' ); + return {}; + + } } - copy( color ) { + } - this.r = color.r; - this.g = color.g; - this.b = color.b; + let _textureId = 0; - return this; + class Texture extends EventDispatcher { - } + constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, colorSpace = NoColorSpace ) { - copySRGBToLinear( color ) { + super(); - this.r = SRGBToLinear( color.r ); - this.g = SRGBToLinear( color.g ); - this.b = SRGBToLinear( color.b ); + this.isTexture = true; - return this; + Object.defineProperty( this, 'id', { value: _textureId ++ } ); - } + this.uuid = generateUUID(); - copyLinearToSRGB( color ) { + this.name = ''; - this.r = LinearToSRGB( color.r ); - this.g = LinearToSRGB( color.g ); - this.b = LinearToSRGB( color.b ); + this.source = new Source( image ); + this.mipmaps = []; - return this; + this.mapping = mapping; + this.channel = 0; - } + this.wrapS = wrapS; + this.wrapT = wrapT; - convertSRGBToLinear() { + this.magFilter = magFilter; + this.minFilter = minFilter; - this.copySRGBToLinear( this ); + this.anisotropy = anisotropy; - return this; + this.format = format; + this.internalFormat = null; + this.type = type; - } + this.offset = new Vector2( 0, 0 ); + this.repeat = new Vector2( 1, 1 ); + this.center = new Vector2( 0, 0 ); + this.rotation = 0; - convertLinearToSRGB() { + this.matrixAutoUpdate = true; + this.matrix = new Matrix3(); - this.copyLinearToSRGB( this ); + 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) - return this; + if ( typeof colorSpace === 'string' ) { - } + this.colorSpace = colorSpace; - getHex( colorSpace = SRGBColorSpace ) { + } else { // @deprecated, r152 - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = colorSpace === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - return clamp( _rgb$1.r * 255, 0, 255 ) << 16 ^ clamp( _rgb$1.g * 255, 0, 255 ) << 8 ^ clamp( _rgb$1.b * 255, 0, 255 ) << 0; + } + + + this.userData = {}; + + this.version = 0; + this.onUpdate = null; + + this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not + this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) } - getHexString( colorSpace = SRGBColorSpace ) { + get image() { - return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); + return this.source.data; } - getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { + set image( value = null ) { - // h,s,l ranges are in 0.0 - 1.0 + this.source.data = value; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + } - const r = _rgb$1.r, g = _rgb$1.g, b = _rgb$1.b; + updateMatrix() { - const max = Math.max( r, g, b ); - const min = Math.min( r, g, b ); + this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); - let hue, saturation; - const lightness = ( min + max ) / 2.0; + } - if ( min === max ) { + clone() { - hue = 0; - saturation = 0; + return new this.constructor().copy( this ); - } else { + } - const delta = max - min; + copy( source ) { - saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); + this.name = source.name; - switch ( max ) { + this.source = source.source; + this.mipmaps = source.mipmaps.slice( 0 ); - case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; - case g: hue = ( b - r ) / delta + 2; break; - case b: hue = ( r - g ) / delta + 4; break; + this.mapping = source.mapping; + this.channel = source.channel; - } + this.wrapS = source.wrapS; + this.wrapT = source.wrapT; - hue /= 6; + this.magFilter = source.magFilter; + this.minFilter = source.minFilter; - } + this.anisotropy = source.anisotropy; - target.h = hue; - target.s = saturation; - target.l = lightness; + this.format = source.format; + this.internalFormat = source.internalFormat; + this.type = source.type; - return target; + 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 ); - getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { + this.generateMipmaps = source.generateMipmaps; + this.premultiplyAlpha = source.premultiplyAlpha; + this.flipY = source.flipY; + this.unpackAlignment = source.unpackAlignment; + this.colorSpace = source.colorSpace; - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - target.r = _rgb$1.r; - target.g = _rgb$1.g; - target.b = _rgb$1.b; + this.needsUpdate = true; - return target; + return this; } - getStyle( colorSpace = SRGBColorSpace ) { + toJSON( meta ) { - ColorManagement.fromWorkingColorSpace( toComponents( this, _rgb$1 ), colorSpace ); + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - if ( colorSpace !== SRGBColorSpace ) { + if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { - // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). - return `color(${ colorSpace } ${ _rgb$1.r } ${ _rgb$1.g } ${ _rgb$1.b })`; + return meta.textures[ this.uuid ]; } - return `rgb(${( _rgb$1.r * 255 ) | 0},${( _rgb$1.g * 255 ) | 0},${( _rgb$1.b * 255 ) | 0})`; + const output = { - } + metadata: { + version: 4.6, + type: 'Texture', + generator: 'Texture.toJSON' + }, - offsetHSL( h, s, l ) { + uuid: this.uuid, + name: this.name, - this.getHSL( _hslA ); + image: this.source.toJSON( meta ).uuid, - _hslA.h += h; _hslA.s += s; _hslA.l += l; + mapping: this.mapping, + channel: this.channel, - this.setHSL( _hslA.h, _hslA.s, _hslA.l ); + repeat: [ this.repeat.x, this.repeat.y ], + offset: [ this.offset.x, this.offset.y ], + center: [ this.center.x, this.center.y ], + rotation: this.rotation, - return this; + wrap: [ this.wrapS, this.wrapT ], - } + format: this.format, + internalFormat: this.internalFormat, + type: this.type, + colorSpace: this.colorSpace, - add( color ) { + minFilter: this.minFilter, + magFilter: this.magFilter, + anisotropy: this.anisotropy, - this.r += color.r; - this.g += color.g; - this.b += color.b; + flipY: this.flipY, - return this; + generateMipmaps: this.generateMipmaps, + premultiplyAlpha: this.premultiplyAlpha, + unpackAlignment: this.unpackAlignment - } + }; - addColors( color1, color2 ) { + if ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData; - this.r = color1.r + color2.r; - this.g = color1.g + color2.g; - this.b = color1.b + color2.b; + if ( ! isRootObject ) { - return this; + meta.textures[ this.uuid ] = output; - } + } - addScalar( s ) { + return output; - this.r += s; - this.g += s; - this.b += s; + } - return this; + dispose() { + + this.dispatchEvent( { type: 'dispose' } ); } - sub( color ) { + transformUv( uv ) { - this.r = Math.max( 0, this.r - color.r ); - this.g = Math.max( 0, this.g - color.g ); - this.b = Math.max( 0, this.b - color.b ); + if ( this.mapping !== UVMapping ) return uv; - return this; + uv.applyMatrix3( this.matrix ); - } + if ( uv.x < 0 || uv.x > 1 ) { - multiply( color ) { + switch ( this.wrapS ) { - this.r *= color.r; - this.g *= color.g; - this.b *= color.b; + case RepeatWrapping: - return this; + uv.x = uv.x - Math.floor( uv.x ); + break; - } + case ClampToEdgeWrapping: - multiplyScalar( s ) { + uv.x = uv.x < 0 ? 0 : 1; + break; - this.r *= s; - this.g *= s; - this.b *= s; + case MirroredRepeatWrapping: - return this; + if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { - } + uv.x = Math.ceil( uv.x ) - uv.x; - lerp( color, alpha ) { + } else { - this.r += ( color.r - this.r ) * alpha; - this.g += ( color.g - this.g ) * alpha; - this.b += ( color.b - this.b ) * alpha; + uv.x = uv.x - Math.floor( uv.x ); - return this; + } - } + break; - lerpColors( color1, color2, alpha ) { + } - this.r = color1.r + ( color2.r - color1.r ) * alpha; - this.g = color1.g + ( color2.g - color1.g ) * alpha; - this.b = color1.b + ( color2.b - color1.b ) * alpha; + } - return this; + if ( uv.y < 0 || uv.y > 1 ) { - } + switch ( this.wrapT ) { - lerpHSL( color, alpha ) { + case RepeatWrapping: - this.getHSL( _hslA ); - color.getHSL( _hslB ); + uv.y = uv.y - Math.floor( uv.y ); + break; - const h = lerp( _hslA.h, _hslB.h, alpha ); - const s = lerp( _hslA.s, _hslB.s, alpha ); - const l = lerp( _hslA.l, _hslB.l, alpha ); + case ClampToEdgeWrapping: - this.setHSL( h, s, l ); + uv.y = uv.y < 0 ? 0 : 1; + break; - return this; + case MirroredRepeatWrapping: - } + if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { - equals( c ) { + uv.y = Math.ceil( uv.y ) - uv.y; - return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); + } else { - } + uv.y = uv.y - Math.floor( uv.y ); - fromArray( array, offset = 0 ) { + } - this.r = array[ offset ]; - this.g = array[ offset + 1 ]; - this.b = array[ offset + 2 ]; + break; - return this; + } - } + } - toArray( array = [], offset = 0 ) { + if ( this.flipY ) { - array[ offset ] = this.r; - array[ offset + 1 ] = this.g; - array[ offset + 2 ] = this.b; + uv.y = 1 - uv.y; - return array; + } + + return uv; } - fromBufferAttribute( attribute, index ) { + set needsUpdate( value ) { - this.r = attribute.getX( index ); - this.g = attribute.getY( index ); - this.b = attribute.getZ( index ); + if ( value === true ) { - return this; + this.version ++; + this.source.needsUpdate = true; + + } } - toJSON() { + get encoding() { // @deprecated, r152 - return this.getHex(); + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + return this.colorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; } - *[ Symbol.iterator ]() { + set encoding( encoding ) { // @deprecated, r152 - yield this.r; - yield this.g; - yield this.b; + warnOnce( 'THREE.Texture: Property .encoding has been replaced by .colorSpace.' ); + this.colorSpace = encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; } } - Color.NAMES = _colorKeywords; + Texture.DEFAULT_IMAGE = null; + Texture.DEFAULT_MAPPING = UVMapping; + Texture.DEFAULT_ANISOTROPY = 1; - let _canvas; + class Vector4 { - class ImageUtils { + constructor( x = 0, y = 0, z = 0, w = 1 ) { - static getDataURL( image ) { + Vector4.prototype.isVector4 = true; - if ( /^data:/i.test( image.src ) ) { - - return image.src; + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + } - if ( typeof HTMLCanvasElement == 'undefined' ) { + get width() { - return image.src; + return this.z; - } + } - let canvas; + set width( value ) { - if ( image instanceof HTMLCanvasElement ) { + this.z = value; - canvas = image; + } - } else { + get height() { - if ( _canvas === undefined ) _canvas = createElementNS( 'canvas' ); + return this.w; - _canvas.width = image.width; - _canvas.height = image.height; + } - const context = _canvas.getContext( '2d' ); + set height( value ) { - if ( image instanceof ImageData ) { + this.w = value; - context.putImageData( image, 0, 0 ); + } - } else { + set( x, y, z, w ) { - context.drawImage( image, 0, 0, image.width, image.height ); + this.x = x; + this.y = y; + this.z = z; + this.w = w; - } + return this; - canvas = _canvas; + } - } + setScalar( scalar ) { - if ( canvas.width > 2048 || canvas.height > 2048 ) { + this.x = scalar; + this.y = scalar; + this.z = scalar; + this.w = scalar; - console.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image ); + return this; - return canvas.toDataURL( 'image/jpeg', 0.6 ); + } - } else { + setX( x ) { - return canvas.toDataURL( 'image/png' ); + this.x = x; - } + return this; } - static sRGBToLinear( image ) { + setY( y ) { - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + this.y = y; - const canvas = createElementNS( 'canvas' ); + return this; - canvas.width = image.width; - canvas.height = image.height; + } - const context = canvas.getContext( '2d' ); - context.drawImage( image, 0, 0, image.width, image.height ); + setZ( z ) { - const imageData = context.getImageData( 0, 0, image.width, image.height ); - const data = imageData.data; + this.z = z; - for ( let i = 0; i < data.length; i ++ ) { + return this; - data[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255; + } - } + setW( w ) { - context.putImageData( imageData, 0, 0 ); + this.w = w; - return canvas; + return this; - } else if ( image.data ) { + } - const data = image.data.slice( 0 ); + setComponent( index, value ) { - for ( let i = 0; i < data.length; i ++ ) { + switch ( index ) { - if ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) { + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + case 3: this.w = value; break; + default: throw new Error( 'index is out of range: ' + index ); - data[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 ); + } - } else { + return this; - // assuming float + } - data[ i ] = SRGBToLinear( data[ i ] ); + getComponent( index ) { - } + switch ( index ) { - } + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + case 3: return this.w; + default: throw new Error( 'index is out of range: ' + index ); - return { - data: data, - width: image.width, - height: image.height - }; + } - } else { + } - console.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' ); - return image; + clone() { - } + return new this.constructor( this.x, this.y, this.z, this.w ); } - } + copy( v ) { - class Source { + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.w = ( v.w !== undefined ) ? v.w : 1; - constructor( data = null ) { + return this; - this.isSource = true; + } - this.uuid = generateUUID(); + add( v ) { - this.data = data; + this.x += v.x; + this.y += v.y; + this.z += v.z; + this.w += v.w; - this.version = 0; + return this; } - set needsUpdate( value ) { - - if ( value === true ) this.version ++; + addScalar( s ) { - } + this.x += s; + this.y += s; + this.z += s; + this.w += s; - toJSON( meta ) { + return this; - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + } - if ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) { + addVectors( a, b ) { - return meta.images[ this.uuid ]; + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; + this.w = a.w + b.w; - } + return this; - const output = { - uuid: this.uuid, - url: '' - }; + } - const data = this.data; + addScaledVector( v, s ) { - if ( data !== null ) { + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; + this.w += v.w * s; - let url; + return this; - if ( Array.isArray( data ) ) { + } - // cube texture + sub( v ) { - url = []; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; + this.w -= v.w; - for ( let i = 0, l = data.length; i < l; i ++ ) { + return this; - if ( data[ i ].isDataTexture ) { + } - url.push( serializeImage( data[ i ].image ) ); + subScalar( s ) { - } else { + this.x -= s; + this.y -= s; + this.z -= s; + this.w -= s; - url.push( serializeImage( data[ i ] ) ); + return this; - } + } - } + subVectors( a, b ) { - } else { + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; + this.w = a.w - b.w; - // texture + return this; - url = serializeImage( data ); + } - } + multiply( v ) { - output.url = url; + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; + this.w *= v.w; - } + return this; - if ( ! isRootObject ) { + } - meta.images[ this.uuid ] = output; + multiplyScalar( scalar ) { - } + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; + this.w *= scalar; - return output; + return this; } - } + applyMatrix4( m ) { - function serializeImage( image ) { + const x = this.x, y = this.y, z = this.z, w = this.w; + const e = m.elements; - if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) || - ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) || - ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) { + 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; - // default images + return this; - return ImageUtils.getDataURL( image ); + } - } else { - - if ( image.data ) { + divideScalar( scalar ) { - // images of DataTexture + return this.multiplyScalar( 1 / scalar ); - return { - data: Array.from( image.data ), - width: image.width, - height: image.height, - type: image.data.constructor.name - }; + } - } else { + setAxisAngleFromQuaternion( q ) { - console.warn( 'THREE.Texture: Unable to serialize Texture.' ); - return {}; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - } + // q is assumed to be normalized - } + this.w = 2 * Math.acos( q.w ); - } + const s = Math.sqrt( 1 - q.w * q.w ); - let textureId = 0; + if ( s < 0.0001 ) { - class Texture extends EventDispatcher { + this.x = 1; + this.y = 0; + this.z = 0; - constructor( image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = Texture.DEFAULT_ANISOTROPY, encoding = LinearEncoding ) { + } else { - super(); + this.x = q.x / s; + this.y = q.y / s; + this.z = q.z / s; - this.isTexture = true; + } - Object.defineProperty( this, 'id', { value: textureId ++ } ); + return this; - this.uuid = generateUUID(); + } - this.name = ''; + setAxisAngleFromRotationMatrix( m ) { - this.source = new Source( image ); - this.mipmaps = []; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - this.mapping = mapping; + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - this.wrapS = wrapS; - this.wrapT = wrapT; + let angle, x, y, z; // variables for result + const epsilon = 0.01, // margin to allow for rounding errors + epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees - this.magFilter = magFilter; - this.minFilter = minFilter; + te = m.elements, - this.anisotropy = anisotropy; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; - this.format = format; - this.internalFormat = null; - this.type = type; + if ( ( Math.abs( m12 - m21 ) < epsilon ) && + ( Math.abs( m13 - m31 ) < epsilon ) && + ( Math.abs( m23 - m32 ) < epsilon ) ) { - this.offset = new Vector2( 0, 0 ); - this.repeat = new Vector2( 1, 1 ); - this.center = new Vector2( 0, 0 ); - this.rotation = 0; + // singularity found + // first check for identity matrix which must have +1 for all terms + // in leading diagonal and zero in other terms - this.matrixAutoUpdate = true; - this.matrix = new Matrix3(); + if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && + ( Math.abs( m13 + m31 ) < epsilon2 ) && + ( Math.abs( m23 + m32 ) < epsilon2 ) && + ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { - 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 singularity is identity matrix so angle = 0 - // Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap. - // - // Also changing the encoding after already used by a Material will not automatically make the Material - // update. You need to explicitly call Material.needsUpdate to trigger it to recompile. - this.encoding = encoding; + this.set( 1, 0, 0, 0 ); - this.userData = {}; + return this; // zero angle, arbitrary axis - this.version = 0; - this.onUpdate = null; + } - this.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not - this.needsPMREMUpdate = false; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures) + // otherwise this singularity is angle = 180 - } + angle = Math.PI; - get image() { + 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; - return this.source.data; + if ( ( xx > yy ) && ( xx > zz ) ) { - } + // m11 is the largest diagonal term - set image( value ) { + if ( xx < epsilon ) { - this.source.data = value; + x = 0; + y = 0.707106781; + z = 0.707106781; - } + } else { - updateMatrix() { + x = Math.sqrt( xx ); + y = xy / x; + z = xz / x; - this.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y ); + } - } + } else if ( yy > zz ) { - clone() { + // m22 is the largest diagonal term - return new this.constructor().copy( this ); + if ( yy < epsilon ) { - } + x = 0.707106781; + y = 0; + z = 0.707106781; - copy( source ) { + } else { - this.name = source.name; + y = Math.sqrt( yy ); + x = xy / y; + z = yz / y; - this.source = source.source; - this.mipmaps = source.mipmaps.slice( 0 ); + } - this.mapping = source.mapping; + } else { - this.wrapS = source.wrapS; - this.wrapT = source.wrapT; + // m33 is the largest diagonal term so base result on this - this.magFilter = source.magFilter; - this.minFilter = source.minFilter; + if ( zz < epsilon ) { - this.anisotropy = source.anisotropy; + x = 0.707106781; + y = 0.707106781; + z = 0; - this.format = source.format; - this.internalFormat = source.internalFormat; - this.type = source.type; + } else { - this.offset.copy( source.offset ); - this.repeat.copy( source.repeat ); - this.center.copy( source.center ); - this.rotation = source.rotation; + z = Math.sqrt( zz ); + x = xz / z; + y = yz / z; - 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.encoding = source.encoding; + } - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + this.set( x, y, z, angle ); - this.needsUpdate = true; + return this; // return 180 deg rotation - return this; + } - } + // as we have reached here there are no singularities so we can handle normally - toJSON( meta ) { + let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + + ( m13 - m31 ) * ( m13 - m31 ) + + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + if ( Math.abs( s ) < 0.001 ) s = 1; - if ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) { + // prevent divide by zero, should not happen if matrix is orthogonal and should be + // caught by singularity test above, but I've left it in just in case - return meta.textures[ this.uuid ]; + this.x = ( m32 - m23 ) / s; + this.y = ( m13 - m31 ) / s; + this.z = ( m21 - m12 ) / s; + this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); - } + return this; - const output = { + } - metadata: { - version: 4.5, - type: 'Texture', - generator: 'Texture.toJSON' - }, + min( v ) { - uuid: this.uuid, - name: this.name, + 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 ); - image: this.source.toJSON( meta ).uuid, + return this; - mapping: this.mapping, + } - repeat: [ this.repeat.x, this.repeat.y ], - offset: [ this.offset.x, this.offset.y ], - center: [ this.center.x, this.center.y ], - rotation: this.rotation, + max( v ) { - wrap: [ this.wrapS, this.wrapT ], + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); + this.w = Math.max( this.w, v.w ); - format: this.format, - type: this.type, - encoding: this.encoding, + return this; - minFilter: this.minFilter, - magFilter: this.magFilter, - anisotropy: this.anisotropy, + } - flipY: this.flipY, + clamp( min, max ) { - premultiplyAlpha: this.premultiplyAlpha, - unpackAlignment: this.unpackAlignment + // assumes min < max, componentwise - }; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + this.w = Math.max( min.w, Math.min( max.w, this.w ) ); - if ( JSON.stringify( this.userData ) !== '{}' ) output.userData = this.userData; + return this; - if ( ! isRootObject ) { + } - meta.textures[ this.uuid ] = output; + clampScalar( minVal, maxVal ) { - } + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - return output; + return this; } - dispose() { + clampLength( min, max ) { - this.dispatchEvent( { type: 'dispose' } ); + const length = this.length(); + + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); } - transformUv( uv ) { + floor() { - if ( this.mapping !== UVMapping ) return uv; + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); + this.w = Math.floor( this.w ); - uv.applyMatrix3( this.matrix ); + return this; - if ( uv.x < 0 || uv.x > 1 ) { + } - switch ( this.wrapS ) { + ceil() { - case RepeatWrapping: + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); + this.w = Math.ceil( this.w ); - uv.x = uv.x - Math.floor( uv.x ); - break; + return this; - case ClampToEdgeWrapping: + } - uv.x = uv.x < 0 ? 0 : 1; - break; + round() { - case MirroredRepeatWrapping: + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); + this.w = Math.round( this.w ); - if ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) { + return this; - uv.x = Math.ceil( uv.x ) - uv.x; + } - } else { + roundToZero() { - uv.x = uv.x - Math.floor( uv.x ); + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); + this.w = Math.trunc( this.w ); - } + return this; - break; + } - } + negate() { - } + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; + this.w = - this.w; - if ( uv.y < 0 || uv.y > 1 ) { + return this; - switch ( this.wrapT ) { + } - case RepeatWrapping: + dot( v ) { - uv.y = uv.y - Math.floor( uv.y ); - break; + return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; - case ClampToEdgeWrapping: + } - uv.y = uv.y < 0 ? 0 : 1; - break; + lengthSq() { - case MirroredRepeatWrapping: + return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; - if ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) { + } - uv.y = Math.ceil( uv.y ) - uv.y; + length() { - } else { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); - uv.y = uv.y - Math.floor( uv.y ); + } - } + manhattanLength() { - break; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); - } + } - } + normalize() { - if ( this.flipY ) { + return this.divideScalar( this.length() || 1 ); - uv.y = 1 - uv.y; + } - } + setLength( length ) { - return uv; + return this.normalize().multiplyScalar( length ); } - set needsUpdate( value ) { - - if ( value === true ) { + lerp( v, alpha ) { - this.version ++; - this.source.needsUpdate = true; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; + this.w += ( v.w - this.w ) * alpha; - } + return this; } - } - - Texture.DEFAULT_IMAGE = null; - Texture.DEFAULT_MAPPING = UVMapping; - Texture.DEFAULT_ANISOTROPY = 1; - - class Vector4 { - - constructor( x = 0, y = 0, z = 0, w = 1 ) { + lerpVectors( v1, v2, alpha ) { - Vector4.prototype.isVector4 = true; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; + this.w = v1.w + ( v2.w - v1.w ) * alpha; - this.x = x; - this.y = y; - this.z = z; - this.w = w; + return this; } - get width() { + equals( v ) { - return this.z; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); } - set width( value ) { - - this.z = value; - - } + fromArray( array, offset = 0 ) { - get height() { + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; + this.w = array[ offset + 3 ]; - return this.w; + return this; } - set height( value ) { + toArray( array = [], offset = 0 ) { - this.w = value; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; + array[ offset + 3 ] = this.w; + + return array; } - set( x, y, z, w ) { + fromBufferAttribute( attribute, index ) { - this.x = x; - this.y = y; - this.z = z; - this.w = w; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); + this.w = attribute.getW( index ); return this; } - setScalar( scalar ) { + random() { - this.x = scalar; - this.y = scalar; - this.z = scalar; - this.w = scalar; + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + this.w = Math.random(); return this; } - setX( x ) { - - this.x = x; + *[ Symbol.iterator ]() { - return this; + yield this.x; + yield this.y; + yield this.z; + yield this.w; } - setY( y ) { + } - this.y = y; + /* + 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 { - return this; + constructor( width = 1, height = 1, options = {} ) { - } + super(); - setZ( z ) { + this.isRenderTarget = true; - this.z = z; + this.width = width; + this.height = height; + this.depth = 1; - return this; + this.scissor = new Vector4( 0, 0, width, height ); + this.scissorTest = false; - } + this.viewport = new Vector4( 0, 0, width, height ); - setW( w ) { + const image = { width: width, height: height, depth: 1 }; - this.w = w; + if ( options.encoding !== undefined ) { - return this; + // @deprecated, r152 + warnOnce( 'THREE.WebGLRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; - } + } - setComponent( index, value ) { + options = Object.assign( { + generateMipmaps: false, + internalFormat: null, + minFilter: LinearFilter, + depthBuffer: true, + stencilBuffer: false, + depthTexture: null, + samples: 0 + }, options ); - switch ( index ) { + this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); + this.texture.isRenderTargetTexture = true; - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - case 3: this.w = value; break; - default: throw new Error( 'index is out of range: ' + index ); + this.texture.flipY = false; + this.texture.generateMipmaps = options.generateMipmaps; + this.texture.internalFormat = options.internalFormat; - } + this.depthBuffer = options.depthBuffer; + this.stencilBuffer = options.stencilBuffer; - return this; + this.depthTexture = options.depthTexture; + + this.samples = options.samples; } - getComponent( index ) { + setSize( width, height, depth = 1 ) { - switch ( index ) { + if ( this.width !== width || this.height !== height || this.depth !== depth ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - case 3: return this.w; - default: throw new Error( 'index is out of range: ' + index ); + this.width = width; + this.height = height; + this.depth = depth; + + this.texture.image.width = width; + this.texture.image.height = height; + this.texture.image.depth = depth; + + this.dispose(); } + this.viewport.set( 0, 0, width, height ); + this.scissor.set( 0, 0, width, height ); + } clone() { - return new this.constructor( this.x, this.y, this.z, this.w ); + return new this.constructor().copy( this ); } - copy( v ) { + copy( source ) { - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.w = ( v.w !== undefined ) ? v.w : 1; + this.width = source.width; + this.height = source.height; + this.depth = source.depth; - return this; + this.scissor.copy( source.scissor ); + this.scissorTest = source.scissorTest; - } + this.viewport.copy( source.viewport ); - add( v ) { + this.texture = source.texture.clone(); + this.texture.isRenderTargetTexture = true; - this.x += v.x; - this.y += v.y; - this.z += v.z; - this.w += v.w; + // ensure image object is not shared, see #20328 - return this; + const image = Object.assign( {}, source.texture.image ); + this.texture.source = new Source( image ); - } + this.depthBuffer = source.depthBuffer; + this.stencilBuffer = source.stencilBuffer; - addScalar( s ) { + if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); - this.x += s; - this.y += s; - this.z += s; - this.w += s; + this.samples = source.samples; return this; } - addVectors( a, b ) { - - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; - this.w = a.w + b.w; + dispose() { - return this; + this.dispatchEvent( { type: 'dispose' } ); } - 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; + } - } + class WebGLRenderTarget extends RenderTarget { - sub( v ) { + constructor( width = 1, height = 1, options = {} ) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - this.w -= v.w; + super( width, height, options ); - return this; + this.isWebGLRenderTarget = true; } - subScalar( s ) { + } - this.x -= s; - this.y -= s; - this.z -= s; - this.w -= s; + class DataArrayTexture extends Texture { - return this; + constructor( data = null, width = 1, height = 1, depth = 1 ) { - } + super( null ); - subVectors( a, b ) { + this.isDataArrayTexture = true; - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; - this.w = a.w - b.w; + this.image = { data, width, height, depth }; - return this; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - } + this.wrapR = ClampToEdgeWrapping; - multiply( v ) { + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; - this.w *= v.w; + } - return this; + } - } + class Data3DTexture extends Texture { - multiplyScalar( scalar ) { + constructor( data = null, width = 1, height = 1, depth = 1 ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; - this.w *= scalar; + // We're going to add .setXXX() methods for setting properties later. + // Users can still set in DataTexture3D directly. + // + // const texture = new THREE.DataTexture3D( data, width, height, depth ); + // texture.anisotropy = 16; + // + // See #14839 - return this; + super( null ); - } + this.isData3DTexture = true; - applyMatrix4( m ) { + this.image = { data, width, height, depth }; - const x = this.x, y = this.y, z = this.z, w = this.w; - const e = m.elements; + this.magFilter = NearestFilter; + this.minFilter = NearestFilter; - 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; + this.wrapR = ClampToEdgeWrapping; - return this; + this.generateMipmaps = false; + this.flipY = false; + this.unpackAlignment = 1; } - divideScalar( scalar ) { + } - return this.multiplyScalar( 1 / scalar ); + class Quaternion { - } + constructor( x = 0, y = 0, z = 0, w = 1 ) { - setAxisAngleFromQuaternion( q ) { + this.isQuaternion = true; - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm + this._x = x; + this._y = y; + this._z = z; + this._w = w; - // q is assumed to be normalized + } - this.w = 2 * Math.acos( q.w ); + static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { - const s = Math.sqrt( 1 - q.w * q.w ); + // fuzz-free, array-based Quaternion SLERP operation - if ( s < 0.0001 ) { + let x0 = src0[ srcOffset0 + 0 ], + y0 = src0[ srcOffset0 + 1 ], + z0 = src0[ srcOffset0 + 2 ], + w0 = src0[ srcOffset0 + 3 ]; - this.x = 1; - this.y = 0; - this.z = 0; + const x1 = src1[ srcOffset1 + 0 ], + y1 = src1[ srcOffset1 + 1 ], + z1 = src1[ srcOffset1 + 2 ], + w1 = src1[ srcOffset1 + 3 ]; - } else { + if ( t === 0 ) { - this.x = q.x / s; - this.y = q.y / s; - this.z = q.z / s; + dst[ dstOffset + 0 ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; + return; } - return this; + if ( t === 1 ) { - } + dst[ dstOffset + 0 ] = x1; + dst[ dstOffset + 1 ] = y1; + dst[ dstOffset + 2 ] = z1; + dst[ dstOffset + 3 ] = w1; + return; - setAxisAngleFromRotationMatrix( m ) { + } - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm + if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + let s = 1 - t; + const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, + dir = ( cos >= 0 ? 1 : - 1 ), + sqrSin = 1 - cos * cos; - let angle, x, y, z; // variables for result - const epsilon = 0.01, // margin to allow for rounding errors - epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees + // Skip the Slerp for tiny steps to avoid numeric problems: + if ( sqrSin > Number.EPSILON ) { - te = m.elements, + const sin = Math.sqrt( sqrSin ), + len = Math.atan2( sin, cos * dir ); - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ]; + s = Math.sin( s * len ) / sin; + t = Math.sin( t * len ) / sin; - if ( ( Math.abs( m12 - m21 ) < epsilon ) && - ( Math.abs( m13 - m31 ) < epsilon ) && - ( Math.abs( m23 - m32 ) < epsilon ) ) { + } - // singularity found - // first check for identity matrix which must have +1 for all terms - // in leading diagonal and zero in other terms + const tDir = t * dir; - if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && - ( Math.abs( m13 + m31 ) < epsilon2 ) && - ( Math.abs( m23 + m32 ) < epsilon2 ) && - ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { + x0 = x0 * s + x1 * tDir; + y0 = y0 * s + y1 * tDir; + z0 = z0 * s + z1 * tDir; + w0 = w0 * s + w1 * tDir; - // this singularity is identity matrix so angle = 0 + // Normalize in case we just did a lerp: + if ( s === 1 - t ) { - this.set( 1, 0, 0, 0 ); + const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); - return this; // zero angle, arbitrary axis + x0 *= f; + y0 *= f; + z0 *= f; + w0 *= f; } - // otherwise this singularity is angle = 180 + } - angle = Math.PI; + dst[ dstOffset ] = x0; + dst[ dstOffset + 1 ] = y0; + dst[ dstOffset + 2 ] = z0; + dst[ dstOffset + 3 ] = w0; - 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 > yy ) && ( xx > zz ) ) { + static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - // m11 is the largest diagonal term + const x0 = src0[ srcOffset0 ]; + const y0 = src0[ srcOffset0 + 1 ]; + const z0 = src0[ srcOffset0 + 2 ]; + const w0 = src0[ srcOffset0 + 3 ]; - if ( xx < epsilon ) { + const x1 = src1[ srcOffset1 ]; + const y1 = src1[ srcOffset1 + 1 ]; + const z1 = src1[ srcOffset1 + 2 ]; + const w1 = src1[ srcOffset1 + 3 ]; - x = 0; - y = 0.707106781; - z = 0.707106781; + dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; + dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; + dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; + dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; - } else { + return dst; - x = Math.sqrt( xx ); - y = xy / x; - z = xz / x; + } - } + get x() { - } else if ( yy > zz ) { + return this._x; - // m22 is the largest diagonal term + } - if ( yy < epsilon ) { + set x( value ) { - x = 0.707106781; - y = 0; - z = 0.707106781; - - } else { - - y = Math.sqrt( yy ); - x = xy / y; - z = yz / y; + this._x = value; + this._onChangeCallback(); - } + } - } else { + get y() { - // m33 is the largest diagonal term so base result on this + return this._y; - if ( zz < epsilon ) { + } - x = 0.707106781; - y = 0.707106781; - z = 0; + set y( value ) { - } else { + this._y = value; + this._onChangeCallback(); - z = Math.sqrt( zz ); - x = xz / z; - y = yz / z; + } - } + get z() { - } + return this._z; - this.set( x, y, z, angle ); + } - return this; // return 180 deg rotation + set z( value ) { - } + this._z = value; + this._onChangeCallback(); - // as we have reached here there are no singularities so we can handle normally + } - let s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + - ( m13 - m31 ) * ( m13 - m31 ) + - ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize + get w() { - if ( Math.abs( s ) < 0.001 ) s = 1; + return this._w; - // prevent divide by zero, should not happen if matrix is orthogonal and should be - // caught by singularity test above, but I've left it in just in case + } - this.x = ( m32 - m23 ) / s; - this.y = ( m13 - m31 ) / s; - this.z = ( m21 - m12 ) / s; - this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); + set w( value ) { - return this; + this._w = value; + this._onChangeCallback(); } - min( v ) { + set( x, y, z, w ) { - 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 ); + this._x = x; + this._y = y; + this._z = z; + this._w = w; + + this._onChangeCallback(); return this; } - max( v ) { - - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); - this.w = Math.max( this.w, v.w ); + clone() { - return this; + return new this.constructor( this._x, this._y, this._z, this._w ); } - clamp( min, max ) { + copy( quaternion ) { - // assumes min < max, componentwise + this._x = quaternion.x; + this._y = quaternion.y; + this._z = quaternion.z; + this._w = quaternion.w; - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - this.w = Math.max( min.w, Math.min( max.w, this.w ) ); + this._onChangeCallback(); return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); - this.w = Math.max( minVal, Math.min( maxVal, this.w ) ); - - return this; + setFromEuler( euler, update = true ) { - } + const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - clampLength( min, max ) { + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m - const length = this.length(); + const cos = Math.cos; + const sin = Math.sin; - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + 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 ); - floor() { + switch ( order ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); - this.w = Math.floor( this.w ); + 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; - return this; + 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; - ceil() { + 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; - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); - this.w = Math.ceil( this.w ); + 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; - return this; + 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 ); - round() { + } - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); - this.w = Math.round( this.w ); + if ( update === true ) this._onChangeCallback(); return this; } - roundToZero() { + setFromAxisAngle( axis, angle ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); - this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - return this; + // assumes axis is normalized - } + const halfAngle = angle / 2, s = Math.sin( halfAngle ); - negate() { + this._x = axis.x * s; + this._y = axis.y * s; + this._z = axis.z * s; + this._w = Math.cos( halfAngle ); - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; - this.w = - this.w; + this._onChangeCallback(); return this; } - dot( v ) { + setFromRotationMatrix( m ) { - return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; + // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - } + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - lengthSq() { + const te = m.elements, - return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; + m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], + m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], + m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], - } + trace = m11 + m22 + m33; - length() { + if ( trace > 0 ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); + const s = 0.5 / Math.sqrt( trace + 1.0 ); - } + this._w = 0.25 / s; + this._x = ( m32 - m23 ) * s; + this._y = ( m13 - m31 ) * s; + this._z = ( m21 - m12 ) * s; - manhattanLength() { + } else if ( m11 > m22 && m11 > m33 ) { - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); + const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); - } + this._w = ( m32 - m23 ) / s; + this._x = 0.25 * s; + this._y = ( m12 + m21 ) / s; + this._z = ( m13 + m31 ) / s; - normalize() { + } else if ( m22 > m33 ) { - return this.divideScalar( this.length() || 1 ); + const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); - } + this._w = ( m13 - m31 ) / s; + this._x = ( m12 + m21 ) / s; + this._y = 0.25 * s; + this._z = ( m23 + m32 ) / s; - setLength( length ) { + } else { - return this.normalize().multiplyScalar( length ); + const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); - } + this._w = ( m21 - m12 ) / s; + this._x = ( m13 + m31 ) / s; + this._y = ( m23 + m32 ) / s; + this._z = 0.25 * s; - lerp( v, alpha ) { + } - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; - this.w += ( v.w - this.w ) * alpha; + this._onChangeCallback(); return this; } - lerpVectors( v1, v2, alpha ) { + setFromUnitVectors( vFrom, vTo ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; - this.w = v1.w + ( v2.w - v1.w ) * alpha; - - return this; - - } + // assumes direction vectors vFrom and vTo are normalized - equals( v ) { + let r = vFrom.dot( vTo ) + 1; - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); + if ( r < Number.EPSILON ) { - } + // vFrom and vTo point in opposite directions - fromArray( array, offset = 0 ) { + r = 0; - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; - this.w = array[ offset + 3 ]; + if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { - return this; + this._x = - vFrom.y; + this._y = vFrom.x; + this._z = 0; + this._w = r; - } + } else { - toArray( array = [], offset = 0 ) { + this._x = 0; + this._y = - vFrom.z; + this._z = vFrom.y; + this._w = r; - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; - array[ offset + 3 ] = this.w; + } - return array; + } else { - } + // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 - fromBufferAttribute( attribute, index ) { + this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; + this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; + this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; + this._w = r; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); - this.w = attribute.getW( index ); + } - return this; + return this.normalize(); } - random() { - - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); - this.w = Math.random(); + angleTo( q ) { - return this; + return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); } - *[ Symbol.iterator ]() { - - yield this.x; - yield this.y; - yield this.z; - yield this.w; + rotateTowards( q, step ) { - } + const angle = this.angleTo( q ); - } + if ( angle === 0 ) return this; - /* - 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 WebGLRenderTarget extends EventDispatcher { + const t = Math.min( 1, step / angle ); - constructor( width = 1, height = 1, options = {} ) { + this.slerp( q, t ); - super(); + return this; - this.isWebGLRenderTarget = true; + } - this.width = width; - this.height = height; - this.depth = 1; + identity() { - this.scissor = new Vector4( 0, 0, width, height ); - this.scissorTest = false; + return this.set( 0, 0, 0, 1 ); - this.viewport = new Vector4( 0, 0, width, height ); + } - const image = { width: width, height: height, depth: 1 }; + invert() { - this.texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); - this.texture.isRenderTargetTexture = true; + // quaternion is assumed to have unit length - this.texture.flipY = false; - this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false; - this.texture.internalFormat = options.internalFormat !== undefined ? options.internalFormat : null; - this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter; + return this.conjugate(); - this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; - this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false; + } - this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null; + conjugate() { - this.samples = options.samples !== undefined ? options.samples : 0; + this._x *= - 1; + this._y *= - 1; + this._z *= - 1; - } + this._onChangeCallback(); - setSize( width, height, depth = 1 ) { + return this; - if ( this.width !== width || this.height !== height || this.depth !== depth ) { + } - this.width = width; - this.height = height; - this.depth = depth; + dot( v ) { - this.texture.image.width = width; - this.texture.image.height = height; - this.texture.image.depth = depth; + return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; - this.dispose(); + } - } + lengthSq() { - this.viewport.set( 0, 0, width, height ); - this.scissor.set( 0, 0, width, height ); + return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; } - clone() { + length() { - return new this.constructor().copy( this ); + return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); } - copy( source ) { + normalize() { - this.width = source.width; - this.height = source.height; - this.depth = source.depth; + let l = this.length(); - this.viewport.copy( source.viewport ); + if ( l === 0 ) { - this.texture = source.texture.clone(); - this.texture.isRenderTargetTexture = true; + this._x = 0; + this._y = 0; + this._z = 0; + this._w = 1; - // ensure image object is not shared, see #20328 + } else { - const image = Object.assign( {}, source.texture.image ); - this.texture.source = new Source( image ); + l = 1 / l; - this.depthBuffer = source.depthBuffer; - this.stencilBuffer = source.stencilBuffer; + this._x = this._x * l; + this._y = this._y * l; + this._z = this._z * l; + this._w = this._w * l; - if ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone(); + } - this.samples = source.samples; + this._onChangeCallback(); return this; } - dispose() { + multiply( q ) { - this.dispatchEvent( { type: 'dispose' } ); + return this.multiplyQuaternions( this, q ); } - } + premultiply( q ) { - class DataArrayTexture extends Texture { + return this.multiplyQuaternions( q, this ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + } - super( null ); + multiplyQuaternions( a, b ) { - this.isDataArrayTexture = true; + // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - this.image = { data, width, height, depth }; + const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; + const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; + this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; + this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; + this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; - this.wrapR = ClampToEdgeWrapping; + this._onChangeCallback(); - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + return this; } - } + slerp( qb, t ) { - class Data3DTexture extends Texture { + if ( t === 0 ) return this; + if ( t === 1 ) return this.copy( qb ); - constructor( data = null, width = 1, height = 1, depth = 1 ) { + const x = this._x, y = this._y, z = this._z, w = this._w; - // We're going to add .setXXX() methods for setting properties later. - // Users can still set in DataTexture3D directly. - // - // const texture = new THREE.DataTexture3D( data, width, height, depth ); - // texture.anisotropy = 16; - // - // See #14839 + // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ - super( null ); + let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; - this.isData3DTexture = true; + if ( cosHalfTheta < 0 ) { - this.image = { data, width, height, depth }; + this._w = - qb._w; + this._x = - qb._x; + this._y = - qb._y; + this._z = - qb._z; - this.magFilter = NearestFilter; - this.minFilter = NearestFilter; + cosHalfTheta = - cosHalfTheta; - this.wrapR = ClampToEdgeWrapping; + } else { - this.generateMipmaps = false; - this.flipY = false; - this.unpackAlignment = 1; + this.copy( qb ); - } + } - } + if ( cosHalfTheta >= 1.0 ) { - class Quaternion { + this._w = w; + this._x = x; + this._y = y; + this._z = z; - constructor( x = 0, y = 0, z = 0, w = 1 ) { + return this; - this.isQuaternion = true; + } - this._x = x; - this._y = y; - this._z = z; - this._w = w; + const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; - } + if ( sqrSinHalfTheta <= Number.EPSILON ) { - static slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) { + 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; - // fuzz-free, array-based Quaternion SLERP operation + this.normalize(); // normalize calls _onChangeCallback() - let x0 = src0[ srcOffset0 + 0 ], - y0 = src0[ srcOffset0 + 1 ], - z0 = src0[ srcOffset0 + 2 ], - w0 = src0[ srcOffset0 + 3 ]; - - const x1 = src1[ srcOffset1 + 0 ], - y1 = src1[ srcOffset1 + 1 ], - z1 = src1[ srcOffset1 + 2 ], - w1 = src1[ srcOffset1 + 3 ]; - - if ( t === 0 ) { - - dst[ dstOffset + 0 ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; - return; + return this; } - if ( t === 1 ) { + const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); + const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); + const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, + ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; - dst[ dstOffset + 0 ] = x1; - dst[ dstOffset + 1 ] = y1; - dst[ dstOffset + 2 ] = z1; - dst[ dstOffset + 3 ] = w1; - return; + this._w = ( w * ratioA + this._w * ratioB ); + this._x = ( x * ratioA + this._x * ratioB ); + this._y = ( y * ratioA + this._y * ratioB ); + this._z = ( z * ratioA + this._z * ratioB ); - } + this._onChangeCallback(); - if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) { + return this; - let s = 1 - t; - const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1, - dir = ( cos >= 0 ? 1 : - 1 ), - sqrSin = 1 - cos * cos; + } - // Skip the Slerp for tiny steps to avoid numeric problems: - if ( sqrSin > Number.EPSILON ) { + slerpQuaternions( qa, qb, t ) { - const sin = Math.sqrt( sqrSin ), - len = Math.atan2( sin, cos * dir ); + return this.copy( qa ).slerp( qb, t ); - s = Math.sin( s * len ) / sin; - t = Math.sin( t * len ) / sin; + } - } + random() { - const tDir = t * dir; + // Derived from http://planning.cs.uiuc.edu/node198.html + // Note, this source uses w, x, y, z ordering, + // so we swap the order below. - x0 = x0 * s + x1 * tDir; - y0 = y0 * s + y1 * tDir; - z0 = z0 * s + z1 * tDir; - w0 = w0 * s + w1 * tDir; + const u1 = Math.random(); + const sqrt1u1 = Math.sqrt( 1 - u1 ); + const sqrtu1 = Math.sqrt( u1 ); - // Normalize in case we just did a lerp: - if ( s === 1 - t ) { + const u2 = 2 * Math.PI * Math.random(); - const f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 ); + const u3 = 2 * Math.PI * Math.random(); - x0 *= f; - y0 *= f; - z0 *= f; - w0 *= f; + return this.set( + sqrt1u1 * Math.cos( u2 ), + sqrtu1 * Math.sin( u3 ), + sqrtu1 * Math.cos( u3 ), + sqrt1u1 * Math.sin( u2 ), + ); - } + } - } + equals( quaternion ) { - dst[ dstOffset ] = x0; - dst[ dstOffset + 1 ] = y0; - dst[ dstOffset + 2 ] = z0; - dst[ dstOffset + 3 ] = w0; + return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); } - static multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) { - - const x0 = src0[ srcOffset0 ]; - const y0 = src0[ srcOffset0 + 1 ]; - const z0 = src0[ srcOffset0 + 2 ]; - const w0 = src0[ srcOffset0 + 3 ]; + fromArray( array, offset = 0 ) { - const x1 = src1[ srcOffset1 ]; - const y1 = src1[ srcOffset1 + 1 ]; - const z1 = src1[ srcOffset1 + 2 ]; - const w1 = src1[ srcOffset1 + 3 ]; + this._x = array[ offset ]; + this._y = array[ offset + 1 ]; + this._z = array[ offset + 2 ]; + this._w = array[ offset + 3 ]; - dst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1; - dst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1; - dst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1; - dst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1; + this._onChangeCallback(); - return dst; + return this; } - get x() { + toArray( array = [], offset = 0 ) { - return this._x; + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._w; - } + return array; - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + fromBufferAttribute( attribute, index ) { - } + this._x = attribute.getX( index ); + this._y = attribute.getY( index ); + this._z = attribute.getZ( index ); + this._w = attribute.getW( index ); - get y() { + this._onChangeCallback(); - return this._y; + return this; } - set y( value ) { + toJSON() { - this._y = value; - this._onChangeCallback(); + return this.toArray(); } - get z() { + _onChange( callback ) { - return this._z; + this._onChangeCallback = callback; + + return this; } - set z( value ) { + _onChangeCallback() {} - this._z = value; - this._onChangeCallback(); + *[ Symbol.iterator ]() { + + yield this._x; + yield this._y; + yield this._z; + yield this._w; } - get w() { + } - return this._w; + class Vector3 { - } + constructor( x = 0, y = 0, z = 0 ) { - set w( value ) { + Vector3.prototype.isVector3 = true; - this._w = value; - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; } - set( x, y, z, w ) { + set( x, y, z ) { - this._x = x; - this._y = y; - this._z = z; - this._w = w; + if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) - this._onChangeCallback(); + this.x = x; + this.y = y; + this.z = z; return this; } - clone() { + setScalar( scalar ) { - return new this.constructor( this._x, this._y, this._z, this._w ); + this.x = scalar; + this.y = scalar; + this.z = scalar; - } + return this; - copy( quaternion ) { + } - this._x = quaternion.x; - this._y = quaternion.y; - this._z = quaternion.z; - this._w = quaternion.w; + setX( x ) { - this._onChangeCallback(); + this.x = x; return this; } - setFromEuler( euler, update ) { - - const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - const cos = Math.cos; - const sin = Math.sin; + setY( y ) { - const c1 = cos( x / 2 ); - const c2 = cos( y / 2 ); - const c3 = cos( z / 2 ); + this.y = y; - const s1 = sin( x / 2 ); - const s2 = sin( y / 2 ); - const s3 = sin( z / 2 ); + return this; - 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; + setZ( z ) { - 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; + this.z = z; - 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; + return this; - 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; + setComponent( index, value ) { - 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; + switch ( index ) { - default: - console.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order ); + case 0: this.x = value; break; + case 1: this.y = value; break; + case 2: this.z = value; break; + default: throw new Error( 'index is out of range: ' + index ); } - if ( update !== false ) this._onChangeCallback(); - return this; } - setFromAxisAngle( axis, angle ) { + getComponent( index ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm + switch ( index ) { - // assumes axis is normalized + case 0: return this.x; + case 1: return this.y; + case 2: return this.z; + default: throw new Error( 'index is out of range: ' + index ); - const halfAngle = angle / 2, s = Math.sin( halfAngle ); + } - this._x = axis.x * s; - this._y = axis.y * s; - this._z = axis.z * s; - this._w = Math.cos( halfAngle ); + } - this._onChangeCallback(); + clone() { - return this; + return new this.constructor( this.x, this.y, this.z ); } - setFromRotationMatrix( m ) { - - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + copy( v ) { - const te = m.elements, + this.x = v.x; + this.y = v.y; + this.z = v.z; - m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ], - m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ], - m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ], + return this; - trace = m11 + m22 + m33; + } - if ( trace > 0 ) { + add( v ) { - const s = 0.5 / Math.sqrt( trace + 1.0 ); + this.x += v.x; + this.y += v.y; + this.z += v.z; - this._w = 0.25 / s; - this._x = ( m32 - m23 ) * s; - this._y = ( m13 - m31 ) * s; - this._z = ( m21 - m12 ) * s; + return this; - } else if ( m11 > m22 && m11 > m33 ) { + } - const s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); + addScalar( s ) { - this._w = ( m32 - m23 ) / s; - this._x = 0.25 * s; - this._y = ( m12 + m21 ) / s; - this._z = ( m13 + m31 ) / s; + this.x += s; + this.y += s; + this.z += s; - } else if ( m22 > m33 ) { + return this; - const s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); + } - this._w = ( m13 - m31 ) / s; - this._x = ( m12 + m21 ) / s; - this._y = 0.25 * s; - this._z = ( m23 + m32 ) / s; + addVectors( a, b ) { - } else { + this.x = a.x + b.x; + this.y = a.y + b.y; + this.z = a.z + b.z; - const s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); + return this; - this._w = ( m21 - m12 ) / s; - this._x = ( m13 + m31 ) / s; - this._y = ( m23 + m32 ) / s; - this._z = 0.25 * s; + } - } + addScaledVector( v, s ) { - this._onChangeCallback(); + this.x += v.x * s; + this.y += v.y * s; + this.z += v.z * s; return this; } - setFromUnitVectors( vFrom, vTo ) { - - // assumes direction vectors vFrom and vTo are normalized + sub( v ) { - let r = vFrom.dot( vTo ) + 1; + this.x -= v.x; + this.y -= v.y; + this.z -= v.z; - if ( r < Number.EPSILON ) { + return this; - // vFrom and vTo point in opposite directions + } - r = 0; + subScalar( s ) { - if ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) { + this.x -= s; + this.y -= s; + this.z -= s; - this._x = - vFrom.y; - this._y = vFrom.x; - this._z = 0; - this._w = r; + return this; - } else { + } - this._x = 0; - this._y = - vFrom.z; - this._z = vFrom.y; - this._w = r; + subVectors( a, b ) { - } + this.x = a.x - b.x; + this.y = a.y - b.y; + this.z = a.z - b.z; - } else { + return this; - // crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3 + } - this._x = vFrom.y * vTo.z - vFrom.z * vTo.y; - this._y = vFrom.z * vTo.x - vFrom.x * vTo.z; - this._z = vFrom.x * vTo.y - vFrom.y * vTo.x; - this._w = r; + multiply( v ) { - } + this.x *= v.x; + this.y *= v.y; + this.z *= v.z; - return this.normalize(); + return this; } - angleTo( q ) { - - return 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) ); - - } + multiplyScalar( scalar ) { - rotateTowards( q, step ) { + this.x *= scalar; + this.y *= scalar; + this.z *= scalar; - const angle = this.angleTo( q ); + return this; - if ( angle === 0 ) return this; + } - const t = Math.min( 1, step / angle ); + multiplyVectors( a, b ) { - this.slerp( q, t ); + this.x = a.x * b.x; + this.y = a.y * b.y; + this.z = a.z * b.z; return this; } - identity() { + applyEuler( euler ) { - return this.set( 0, 0, 0, 1 ); + return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); } - invert() { - - // quaternion is assumed to have unit length + applyAxisAngle( axis, angle ) { - return this.conjugate(); + return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); } - conjugate() { + applyMatrix3( m ) { - this._x *= - 1; - this._y *= - 1; - this._z *= - 1; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - this._onChangeCallback(); + 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; } - dot( v ) { + applyNormalMatrix( m ) { - return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w; + return this.applyMatrix3( m ).normalize(); } - lengthSq() { + applyMatrix4( m ) { - return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - } + const w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); - length() { + 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 Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); + return this; } - normalize() { - - let l = this.length(); + applyQuaternion( q ) { - if ( l === 0 ) { + // quaternion q is assumed to have unit length - this._x = 0; - this._y = 0; - this._z = 0; - this._w = 1; + const vx = this.x, vy = this.y, vz = this.z; + const qx = q.x, qy = q.y, qz = q.z, qw = q.w; - } else { + // 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 ); - l = 1 / l; + // v + q.w * t + cross( q.xyz, t ); + this.x = vx + qw * tx + qy * tz - qz * ty; + this.y = vy + qw * ty + qz * tx - qx * tz; + this.z = vz + qw * tz + qx * ty - qy * tx; - this._x = this._x * l; - this._y = this._y * l; - this._z = this._z * l; - this._w = this._w * l; + return this; - } + } - this._onChangeCallback(); + project( camera ) { - return this; + return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); } - multiply( q ) { + unproject( camera ) { - return this.multiplyQuaternions( this, q ); + return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); } - premultiply( q ) { + transformDirection( m ) { - return this.multiplyQuaternions( q, this ); + // input: THREE.Matrix4 affine matrix + // vector interpreted as a direction - } + const x = this.x, y = this.y, z = this.z; + const e = m.elements; - multiplyQuaternions( a, b ) { + 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; - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm + return this.normalize(); - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; - const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; + } - this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; - this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; - this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; - this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; + divide( v ) { - this._onChangeCallback(); + this.x /= v.x; + this.y /= v.y; + this.z /= v.z; return this; } - slerp( qb, t ) { + divideScalar( scalar ) { - if ( t === 0 ) return this; - if ( t === 1 ) return this.copy( qb ); + return this.multiplyScalar( 1 / scalar ); - const x = this._x, y = this._y, z = this._z, w = this._w; + } - // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ + min( v ) { - let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; + this.x = Math.min( this.x, v.x ); + this.y = Math.min( this.y, v.y ); + this.z = Math.min( this.z, v.z ); - if ( cosHalfTheta < 0 ) { - - this._w = - qb._w; - this._x = - qb._x; - this._y = - qb._y; - this._z = - qb._z; - - cosHalfTheta = - cosHalfTheta; - - } else { - - this.copy( qb ); - - } - - if ( cosHalfTheta >= 1.0 ) { + return this; - this._w = w; - this._x = x; - this._y = y; - this._z = z; + } - return this; + max( v ) { - } + this.x = Math.max( this.x, v.x ); + this.y = Math.max( this.y, v.y ); + this.z = Math.max( this.z, v.z ); - const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta; + return this; - if ( sqrSinHalfTheta <= Number.EPSILON ) { + } - 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; + clamp( min, max ) { - this.normalize(); - this._onChangeCallback(); + // assumes min < max, componentwise - return this; + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); - } + return this; - const sinHalfTheta = Math.sqrt( sqrSinHalfTheta ); - const halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta ); - const ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, - ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; + } - this._w = ( w * ratioA + this._w * ratioB ); - this._x = ( x * ratioA + this._x * ratioB ); - this._y = ( y * ratioA + this._y * ratioB ); - this._z = ( z * ratioA + this._z * ratioB ); + clampScalar( minVal, maxVal ) { - this._onChangeCallback(); + this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); + this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); + this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); return this; } - slerpQuaternions( qa, qb, t ) { - - return this.copy( qa ).slerp( qb, t ); - - } + clampLength( min, max ) { - random() { + const length = this.length(); - // Derived from http://planning.cs.uiuc.edu/node198.html - // Note, this source uses w, x, y, z ordering, - // so we swap the order below. + return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); - const u1 = Math.random(); - const sqrt1u1 = Math.sqrt( 1 - u1 ); - const sqrtu1 = Math.sqrt( u1 ); + } - const u2 = 2 * Math.PI * Math.random(); + floor() { - const u3 = 2 * Math.PI * Math.random(); + this.x = Math.floor( this.x ); + this.y = Math.floor( this.y ); + this.z = Math.floor( this.z ); - return this.set( - sqrt1u1 * Math.cos( u2 ), - sqrtu1 * Math.sin( u3 ), - sqrtu1 * Math.cos( u3 ), - sqrt1u1 * Math.sin( u2 ), - ); + return this; } - equals( quaternion ) { + ceil() { - return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); + this.x = Math.ceil( this.x ); + this.y = Math.ceil( this.y ); + this.z = Math.ceil( this.z ); - } + return this; - fromArray( array, offset = 0 ) { + } - this._x = array[ offset ]; - this._y = array[ offset + 1 ]; - this._z = array[ offset + 2 ]; - this._w = array[ offset + 3 ]; + round() { - this._onChangeCallback(); + this.x = Math.round( this.x ); + this.y = Math.round( this.y ); + this.z = Math.round( this.z ); return this; } - toArray( array = [], offset = 0 ) { + roundToZero() { - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._w; + this.x = Math.trunc( this.x ); + this.y = Math.trunc( this.y ); + this.z = Math.trunc( this.z ); - return array; + return this; } - fromBufferAttribute( attribute, index ) { + negate() { - this._x = attribute.getX( index ); - this._y = attribute.getY( index ); - this._z = attribute.getZ( index ); - this._w = attribute.getW( index ); + this.x = - this.x; + this.y = - this.y; + this.z = - this.z; return this; } - _onChange( callback ) { - - this._onChangeCallback = callback; + dot( v ) { - return this; + return this.x * v.x + this.y * v.y + this.z * v.z; } - _onChangeCallback() {} + // TODO lengthSquared? - *[ Symbol.iterator ]() { + lengthSq() { - yield this._x; - yield this._y; - yield this._z; - yield this._w; + return this.x * this.x + this.y * this.y + this.z * this.z; } - } + length() { - class Vector3 { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); - constructor( x = 0, y = 0, z = 0 ) { + } - Vector3.prototype.isVector3 = true; + manhattanLength() { - this.x = x; - this.y = y; - this.z = z; + return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); } - set( x, y, z ) { + normalize() { - if ( z === undefined ) z = this.z; // sprite.scale.set(x,y) + return this.divideScalar( this.length() || 1 ); - this.x = x; - this.y = y; - this.z = z; + } - return this; + setLength( length ) { + + return this.normalize().multiplyScalar( length ); } - setScalar( scalar ) { + lerp( v, alpha ) { - this.x = scalar; - this.y = scalar; - this.z = scalar; + this.x += ( v.x - this.x ) * alpha; + this.y += ( v.y - this.y ) * alpha; + this.z += ( v.z - this.z ) * alpha; return this; } - setX( x ) { + lerpVectors( v1, v2, alpha ) { - this.x = x; + this.x = v1.x + ( v2.x - v1.x ) * alpha; + this.y = v1.y + ( v2.y - v1.y ) * alpha; + this.z = v1.z + ( v2.z - v1.z ) * alpha; return this; } - setY( y ) { - - this.y = y; + cross( v ) { - return this; + return this.crossVectors( this, v ); } - setZ( z ) { + crossVectors( a, b ) { - this.z = z; + 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; } - setComponent( index, value ) { + projectOnVector( v ) { - switch ( index ) { + const denominator = v.lengthSq(); - case 0: this.x = value; break; - case 1: this.y = value; break; - case 2: this.z = value; break; - default: throw new Error( 'index is out of range: ' + index ); + if ( denominator === 0 ) return this.set( 0, 0, 0 ); - } + const scalar = v.dot( this ) / denominator; - return this; + return this.copy( v ).multiplyScalar( scalar ); } - getComponent( index ) { - - switch ( index ) { + projectOnPlane( planeNormal ) { - case 0: return this.x; - case 1: return this.y; - case 2: return this.z; - default: throw new Error( 'index is out of range: ' + index ); + _vector$c.copy( this ).projectOnVector( planeNormal ); - } + return this.sub( _vector$c ); } - clone() { + reflect( normal ) { - return new this.constructor( this.x, this.y, this.z ); + // reflect incident vector off plane orthogonal to normal + // normal is assumed to have unit length - } + return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); - copy( v ) { + } - this.x = v.x; - this.y = v.y; - this.z = v.z; + angleTo( v ) { - return this; + const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); - } + if ( denominator === 0 ) return Math.PI / 2; - add( v ) { + const theta = this.dot( v ) / denominator; - this.x += v.x; - this.y += v.y; - this.z += v.z; + // clamp, to handle numerical problems - return this; + return Math.acos( clamp( theta, - 1, 1 ) ); } - addScalar( s ) { - - this.x += s; - this.y += s; - this.z += s; + distanceTo( v ) { - return this; + return Math.sqrt( this.distanceToSquared( v ) ); } - addVectors( a, b ) { + distanceToSquared( v ) { - this.x = a.x + b.x; - this.y = a.y + b.y; - this.z = a.z + b.z; + const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return this; + return dx * dx + dy * dy + dz * dz; } - addScaledVector( v, s ) { - - this.x += v.x * s; - this.y += v.y * s; - this.z += v.z * s; + manhattanDistanceTo( v ) { - return this; + return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); } - sub( v ) { - - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; + setFromSpherical( s ) { - return this; + return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); } - subScalar( s ) { + setFromSphericalCoords( radius, phi, theta ) { - this.x -= s; - this.y -= s; - this.z -= s; + const sinPhiRadius = Math.sin( phi ) * radius; + + this.x = sinPhiRadius * Math.sin( theta ); + this.y = Math.cos( phi ) * radius; + this.z = sinPhiRadius * Math.cos( theta ); return this; } - subVectors( a, b ) { - - this.x = a.x - b.x; - this.y = a.y - b.y; - this.z = a.z - b.z; + setFromCylindrical( c ) { - return this; + return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); } - multiply( v ) { + setFromCylindricalCoords( radius, theta, y ) { - this.x *= v.x; - this.y *= v.y; - this.z *= v.z; + this.x = radius * Math.sin( theta ); + this.y = y; + this.z = radius * Math.cos( theta ); return this; } - multiplyScalar( scalar ) { + setFromMatrixPosition( m ) { - this.x *= scalar; - this.y *= scalar; - this.z *= scalar; + const e = m.elements; + + this.x = e[ 12 ]; + this.y = e[ 13 ]; + this.z = e[ 14 ]; return this; } - multiplyVectors( a, b ) { + setFromMatrixScale( m ) { - this.x = a.x * b.x; - this.y = a.y * b.y; - this.z = a.z * b.z; + const sx = this.setFromMatrixColumn( m, 0 ).length(); + const sy = this.setFromMatrixColumn( m, 1 ).length(); + const sz = this.setFromMatrixColumn( m, 2 ).length(); + + this.x = sx; + this.y = sy; + this.z = sz; return this; } - applyEuler( euler ) { + setFromMatrixColumn( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromEuler( euler ) ); + return this.fromArray( m.elements, index * 4 ); } - applyAxisAngle( axis, angle ) { + setFromMatrix3Column( m, index ) { - return this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) ); + return this.fromArray( m.elements, index * 3 ); } - applyMatrix3( m ) { - - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + setFromEuler( e ) { - 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; + this.x = e._x; + this.y = e._y; + this.z = e._z; return this; } - applyNormalMatrix( m ) { + setFromColor( c ) { - return this.applyMatrix3( m ).normalize(); + this.x = c.r; + this.y = c.g; + this.z = c.b; + + return this; } - applyMatrix4( m ) { + equals( v ) { - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); - 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; + fromArray( array, offset = 0 ) { + + this.x = array[ offset ]; + this.y = array[ offset + 1 ]; + this.z = array[ offset + 2 ]; return this; } - applyQuaternion( q ) { + toArray( array = [], offset = 0 ) { - const x = this.x, y = this.y, z = this.z; - const qx = q.x, qy = q.y, qz = q.z, qw = q.w; + array[ offset ] = this.x; + array[ offset + 1 ] = this.y; + array[ offset + 2 ] = this.z; - // calculate quat * vector + return array; - const ix = qw * x + qy * z - qz * y; - const iy = qw * y + qz * x - qx * z; - const iz = qw * z + qx * y - qy * x; - const iw = - qx * x - qy * y - qz * z; + } - // calculate result * inverse quat + fromBufferAttribute( attribute, index ) { - this.x = ix * qw + iw * - qx + iy * - qz - iz * - qy; - this.y = iy * qw + iw * - qy + iz * - qx - ix * - qz; - this.z = iz * qw + iw * - qz + ix * - qy - iy * - qx; + this.x = attribute.getX( index ); + this.y = attribute.getY( index ); + this.z = attribute.getZ( index ); return this; } - project( camera ) { + random() { - return this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix ); + this.x = Math.random(); + this.y = Math.random(); + this.z = Math.random(); + + return this; } - unproject( camera ) { + randomDirection() { - return this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld ); + // Derived from https://mathworld.wolfram.com/SpherePointPicking.html - } + const u = ( Math.random() - 0.5 ) * 2; + const t = Math.random() * Math.PI * 2; + const f = Math.sqrt( 1 - u ** 2 ); - transformDirection( m ) { + this.x = f * Math.cos( t ); + this.y = f * Math.sin( t ); + this.z = u; - // input: THREE.Matrix4 affine matrix - // vector interpreted as a direction + return this; - const x = this.x, y = this.y, z = this.z; - const e = m.elements; + } - 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; + *[ Symbol.iterator ]() { - return this.normalize(); + yield this.x; + yield this.y; + yield this.z; } - divide( v ) { + } - this.x /= v.x; - this.y /= v.y; - this.z /= v.z; + const _vector$c = /*@__PURE__*/ new Vector3(); + const _quaternion$4 = /*@__PURE__*/ new Quaternion(); - return this; + class Box3 { - } + constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { - divideScalar( scalar ) { + this.isBox3 = true; - return this.multiplyScalar( 1 / scalar ); + this.min = min; + this.max = max; } - min( v ) { + set( min, max ) { - 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.min.copy( min ); + this.max.copy( max ); return this; } - max( v ) { + setFromArray( array ) { - this.x = Math.max( this.x, v.x ); - this.y = Math.max( this.y, v.y ); - this.z = Math.max( this.z, v.z ); + this.makeEmpty(); + + for ( let i = 0, il = array.length; i < il; i += 3 ) { + + this.expandByPoint( _vector$b.fromArray( array, i ) ); + + } return this; } - clamp( min, max ) { + setFromBufferAttribute( attribute ) { - // assumes min < max, componentwise + this.makeEmpty(); - this.x = Math.max( min.x, Math.min( max.x, this.x ) ); - this.y = Math.max( min.y, Math.min( max.y, this.y ) ); - this.z = Math.max( min.z, Math.min( max.z, this.z ) ); + for ( let i = 0, il = attribute.count; i < il; i ++ ) { + + this.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) ); + + } return this; } - clampScalar( minVal, maxVal ) { - - this.x = Math.max( minVal, Math.min( maxVal, this.x ) ); - this.y = Math.max( minVal, Math.min( maxVal, this.y ) ); - this.z = Math.max( minVal, Math.min( maxVal, this.z ) ); + setFromPoints( points ) { - return this; + this.makeEmpty(); - } + for ( let i = 0, il = points.length; i < il; i ++ ) { - clampLength( min, max ) { + this.expandByPoint( points[ i ] ); - const length = this.length(); + } - return this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) ); + return this; } - floor() { + setFromCenterAndSize( center, size ) { - this.x = Math.floor( this.x ); - this.y = Math.floor( this.y ); - this.z = Math.floor( this.z ); + const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + + this.min.copy( center ).sub( halfSize ); + this.max.copy( center ).add( halfSize ); return this; } - ceil() { + setFromObject( object, precise = false ) { - this.x = Math.ceil( this.x ); - this.y = Math.ceil( this.y ); - this.z = Math.ceil( this.z ); + this.makeEmpty(); - return this; + return this.expandByObject( object, precise ); } - round() { - - this.x = Math.round( this.x ); - this.y = Math.round( this.y ); - this.z = Math.round( this.z ); + clone() { - return this; + return new this.constructor().copy( this ); } - roundToZero() { + copy( box ) { - this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); - this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); - this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); + this.min.copy( box.min ); + this.max.copy( box.max ); return this; } - negate() { + makeEmpty() { - this.x = - this.x; - this.y = - this.y; - this.z = - this.z; + this.min.x = this.min.y = this.min.z = + Infinity; + this.max.x = this.max.y = this.max.z = - Infinity; return this; } - dot( v ) { + isEmpty() { - return this.x * v.x + this.y * v.y + this.z * v.z; + // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - } + return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); - // TODO lengthSquared? + } - lengthSq() { + getCenter( target ) { - return this.x * this.x + this.y * this.y + this.z * this.z; + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); } - length() { + getSize( target ) { - return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); + return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); } - manhattanLength() { - - return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); - - } + expandByPoint( point ) { - normalize() { + this.min.min( point ); + this.max.max( point ); - return this.divideScalar( this.length() || 1 ); + return this; } - setLength( length ) { + expandByVector( vector ) { - return this.normalize().multiplyScalar( length ); + this.min.sub( vector ); + this.max.add( vector ); + + return this; } - lerp( v, alpha ) { + expandByScalar( scalar ) { - this.x += ( v.x - this.x ) * alpha; - this.y += ( v.y - this.y ) * alpha; - this.z += ( v.z - this.z ) * alpha; + this.min.addScalar( - scalar ); + this.max.addScalar( scalar ); return this; } - lerpVectors( v1, v2, alpha ) { + expandByObject( object, precise = false ) { - this.x = v1.x + ( v2.x - v1.x ) * alpha; - this.y = v1.y + ( v2.y - v1.y ) * alpha; - this.z = v1.z + ( v2.z - v1.z ) * alpha; + // Computes the world-axis-aligned bounding box of an object (including its children), + // accounting for both the object's, and children's, world transforms - return this; + object.updateWorldMatrix( false, false ); - } + const geometry = object.geometry; - cross( v ) { + if ( geometry !== undefined ) { - return this.crossVectors( this, v ); + const positionAttribute = geometry.getAttribute( 'position' ); - } + // precise AABB computation based on vertex data requires at least a position attribute. + // instancing isn't supported so far and uses the normal (conservative) code path. - crossVectors( a, b ) { + if ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) { - const ax = a.x, ay = a.y, az = a.z; - const bx = b.x, by = b.y, bz = b.z; + for ( let i = 0, l = positionAttribute.count; i < l; i ++ ) { - this.x = ay * bz - az * by; - this.y = az * bx - ax * bz; - this.z = ax * by - ay * bx; + if ( object.isMesh === true ) { - return this; + object.getVertexPosition( i, _vector$b ); - } + } else { - projectOnVector( v ) { + _vector$b.fromBufferAttribute( positionAttribute, i ); - const denominator = v.lengthSq(); + } - if ( denominator === 0 ) return this.set( 0, 0, 0 ); + _vector$b.applyMatrix4( object.matrixWorld ); + this.expandByPoint( _vector$b ); - const scalar = v.dot( this ) / denominator; + } - return this.copy( v ).multiplyScalar( scalar ); + } else { - } + if ( object.boundingBox !== undefined ) { - projectOnPlane( planeNormal ) { + // object-level bounding box - _vector$c.copy( this ).projectOnVector( planeNormal ); + if ( object.boundingBox === null ) { - return this.sub( _vector$c ); + object.computeBoundingBox(); - } + } - reflect( normal ) { + _box$4.copy( object.boundingBox ); - // reflect incident vector off plane orthogonal to normal - // normal is assumed to have unit length - return this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); + } else { - } + // geometry-level bounding box - angleTo( v ) { + if ( geometry.boundingBox === null ) { - const denominator = Math.sqrt( this.lengthSq() * v.lengthSq() ); + geometry.computeBoundingBox(); - if ( denominator === 0 ) return Math.PI / 2; + } - const theta = this.dot( v ) / denominator; + _box$4.copy( geometry.boundingBox ); - // clamp, to handle numerical problems + } - return Math.acos( clamp( theta, - 1, 1 ) ); + _box$4.applyMatrix4( object.matrixWorld ); - } + this.union( _box$4 ); - distanceTo( v ) { + } - return Math.sqrt( this.distanceToSquared( v ) ); + } - } + const children = object.children; - distanceToSquared( v ) { + for ( let i = 0, l = children.length; i < l; i ++ ) { - const dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; + this.expandByObject( children[ i ], precise ); - return dx * dx + dy * dy + dz * dz; + } + + return this; } - manhattanDistanceTo( v ) { + containsPoint( point ) { - return Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z ); + return point.x < this.min.x || point.x > this.max.x || + point.y < this.min.y || point.y > this.max.y || + point.z < this.min.z || point.z > this.max.z ? false : true; } - setFromSpherical( s ) { + containsBox( box ) { - return this.setFromSphericalCoords( s.radius, s.phi, s.theta ); + return this.min.x <= box.min.x && box.max.x <= this.max.x && + this.min.y <= box.min.y && box.max.y <= this.max.y && + this.min.z <= box.min.z && box.max.z <= this.max.z; } - setFromSphericalCoords( radius, phi, theta ) { - - const sinPhiRadius = Math.sin( phi ) * radius; + getParameter( point, target ) { - this.x = sinPhiRadius * Math.sin( theta ); - this.y = Math.cos( phi ) * radius; - this.z = sinPhiRadius * Math.cos( theta ); + // This can potentially have a divide by zero if the box + // has a size dimension of 0. - return this; + 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 ) + ); } - setFromCylindrical( c ) { + intersectsBox( box ) { - return this.setFromCylindricalCoords( c.radius, c.theta, c.y ); + // using 6 splitting planes to rule out intersections. + return box.max.x < this.min.x || box.min.x > this.max.x || + box.max.y < this.min.y || box.min.y > this.max.y || + box.max.z < this.min.z || box.min.z > this.max.z ? false : true; } - setFromCylindricalCoords( radius, theta, y ) { + intersectsSphere( sphere ) { - this.x = radius * Math.sin( theta ); - this.y = y; - this.z = radius * Math.cos( theta ); + // Find the point on the AABB closest to the sphere center. + this.clampPoint( sphere.center, _vector$b ); - return this; + // If that point is inside the sphere, the AABB and sphere intersect. + return _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius ); } - setFromMatrixPosition( m ) { + intersectsPlane( plane ) { - const e = m.elements; + // We compute the minimum and maximum dot product values. If those values + // are on the same side (back or front) of the plane, then there is no intersection. - this.x = e[ 12 ]; - this.y = e[ 13 ]; - this.z = e[ 14 ]; + let min, max; - return this; + if ( plane.normal.x > 0 ) { - } + min = plane.normal.x * this.min.x; + max = plane.normal.x * this.max.x; - setFromMatrixScale( m ) { + } else { - const sx = this.setFromMatrixColumn( m, 0 ).length(); - const sy = this.setFromMatrixColumn( m, 1 ).length(); - const sz = this.setFromMatrixColumn( m, 2 ).length(); + min = plane.normal.x * this.max.x; + max = plane.normal.x * this.min.x; - this.x = sx; - this.y = sy; - this.z = sz; + } - return this; + if ( plane.normal.y > 0 ) { - } + min += plane.normal.y * this.min.y; + max += plane.normal.y * this.max.y; - setFromMatrixColumn( m, index ) { + } else { - return this.fromArray( m.elements, index * 4 ); + min += plane.normal.y * this.max.y; + max += plane.normal.y * this.min.y; - } + } - setFromMatrix3Column( m, index ) { + if ( plane.normal.z > 0 ) { - return this.fromArray( m.elements, index * 3 ); + min += plane.normal.z * this.min.z; + max += plane.normal.z * this.max.z; - } + } else { - setFromEuler( e ) { + min += plane.normal.z * this.max.z; + max += plane.normal.z * this.min.z; - this.x = e._x; - this.y = e._y; - this.z = e._z; + } - return this; + return ( min <= - plane.constant && max >= - plane.constant ); } - equals( v ) { + intersectsTriangle( triangle ) { - return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); + if ( this.isEmpty() ) { - } + return false; - fromArray( array, offset = 0 ) { + } - this.x = array[ offset ]; - this.y = array[ offset + 1 ]; - this.z = array[ offset + 2 ]; + // compute box center and extents + this.getCenter( _center ); + _extents.subVectors( this.max, _center ); - return this; + // translate triangle to aabb origin + _v0$2.subVectors( triangle.a, _center ); + _v1$7.subVectors( triangle.b, _center ); + _v2$4.subVectors( triangle.c, _center ); - } + // compute edge vectors for triangle + _f0.subVectors( _v1$7, _v0$2 ); + _f1.subVectors( _v2$4, _v1$7 ); + _f2.subVectors( _v0$2, _v2$4 ); - toArray( array = [], offset = 0 ) { + // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb + // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation + // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) + let axes = [ + 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, + _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, + - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 + ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - array[ offset ] = this.x; - array[ offset + 1 ] = this.y; - array[ offset + 2 ] = this.z; + return false; - return array; + } - } + // test 3 face normals from the aabb + axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; + if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { - fromBufferAttribute( attribute, index ) { + return false; - this.x = attribute.getX( index ); - this.y = attribute.getY( index ); - this.z = attribute.getZ( index ); + } - return this; + // finally testing the face normal of the triangle + // use already existing triangle edge vectors here + _triangleNormal.crossVectors( _f0, _f1 ); + axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + + return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); } - random() { + clampPoint( point, target ) { - this.x = Math.random(); - this.y = Math.random(); - this.z = Math.random(); + return target.copy( point ).clamp( this.min, this.max ); - return this; + } + + distanceToPoint( point ) { + + return this.clampPoint( point, _vector$b ).distanceTo( point ); } - randomDirection() { + getBoundingSphere( target ) { - // Derived from https://mathworld.wolfram.com/SpherePointPicking.html + if ( this.isEmpty() ) { - const u = ( Math.random() - 0.5 ) * 2; - const t = Math.random() * Math.PI * 2; - const f = Math.sqrt( 1 - u ** 2 ); + target.makeEmpty(); - this.x = f * Math.cos( t ); - this.y = f * Math.sin( t ); - this.z = u; + } else { - return this; + this.getCenter( target.center ); - } + target.radius = this.getSize( _vector$b ).length() * 0.5; - *[ Symbol.iterator ]() { + } - yield this.x; - yield this.y; - yield this.z; + return target; } - } + intersect( box ) { - const _vector$c = /*@__PURE__*/ new Vector3(); - const _quaternion$4 = /*@__PURE__*/ new Quaternion(); + this.min.max( box.min ); + this.max.min( box.max ); - class Box3 { + // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. + if ( this.isEmpty() ) this.makeEmpty(); - constructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) { + return this; - this.isBox3 = true; + } - this.min = min; - this.max = max; + union( box ) { + + this.min.min( box.min ); + this.max.max( box.max ); + + return this; } - set( min, max ) { + applyMatrix4( matrix ) { - this.min.copy( min ); - this.max.copy( max ); + // transform of empty box is an empty box. + if ( this.isEmpty() ) return this; + + // NOTE: I am using a binary pattern to specify all 2^3 combinations below + _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 + _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 + _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 + _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 + _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 + _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 + _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 + _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + + this.setFromPoints( _points ); return this; } - setFromArray( array ) { + translate( offset ) { - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + this.min.add( offset ); + this.max.add( offset ); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + return this; - for ( let i = 0, l = array.length; i < l; i += 3 ) { + } - const x = array[ i ]; - const y = array[ i + 1 ]; - const z = array[ i + 2 ]; + equals( box ) { - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + return box.min.equals( this.min ) && box.max.equals( this.max ); - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + } - } + } - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + 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() + ]; - return this; + const _vector$b = /*@__PURE__*/ new Vector3(); - } + const _box$4 = /*@__PURE__*/ new Box3(); - setFromBufferAttribute( attribute ) { + // triangle centered vertices - let minX = + Infinity; - let minY = + Infinity; - let minZ = + Infinity; + const _v0$2 = /*@__PURE__*/ new Vector3(); + const _v1$7 = /*@__PURE__*/ new Vector3(); + const _v2$4 = /*@__PURE__*/ new Vector3(); - let maxX = - Infinity; - let maxY = - Infinity; - let maxZ = - Infinity; + // triangle edge vectors - for ( let i = 0, l = attribute.count; i < l; i ++ ) { + const _f0 = /*@__PURE__*/ new Vector3(); + const _f1 = /*@__PURE__*/ new Vector3(); + const _f2 = /*@__PURE__*/ new Vector3(); - const x = attribute.getX( i ); - const y = attribute.getY( i ); - const z = attribute.getZ( i ); + const _center = /*@__PURE__*/ new Vector3(); + const _extents = /*@__PURE__*/ new Vector3(); + const _triangleNormal = /*@__PURE__*/ new Vector3(); + const _testAxis = /*@__PURE__*/ new Vector3(); - if ( x < minX ) minX = x; - if ( y < minY ) minY = y; - if ( z < minZ ) minZ = z; + function satForAxes( axes, v0, v1, v2, extents ) { - if ( x > maxX ) maxX = x; - if ( y > maxY ) maxY = y; - if ( z > maxZ ) maxZ = z; + for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { - } + _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 ) { - this.min.set( minX, minY, minZ ); - this.max.set( maxX, maxY, maxZ ); + // points of the projected triangle are outside the projected half-length of the aabb + // the axis is separating and we can exit + return false; - return this; + } } - setFromPoints( points ) { + return true; - this.makeEmpty(); + } - for ( let i = 0, il = points.length; i < il; i ++ ) { + const _box$3 = /*@__PURE__*/ new Box3(); + const _v1$6 = /*@__PURE__*/ new Vector3(); + const _v2$3 = /*@__PURE__*/ new Vector3(); - this.expandByPoint( points[ i ] ); + class Sphere { - } + constructor( center = new Vector3(), radius = - 1 ) { - return this; + this.isSphere = true; - } + this.center = center; + this.radius = radius; - setFromCenterAndSize( center, size ) { + } - const halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 ); + set( center, radius ) { - this.min.copy( center ).sub( halfSize ); - this.max.copy( center ).add( halfSize ); + this.center.copy( center ); + this.radius = radius; return this; } - setFromObject( object, precise = false ) { + setFromPoints( points, optionalCenter ) { - this.makeEmpty(); + const center = this.center; - return this.expandByObject( object, precise ); + if ( optionalCenter !== undefined ) { - } + center.copy( optionalCenter ); - clone() { + } else { - return new this.constructor().copy( this ); + _box$3.setFromPoints( points ).getCenter( center ); - } + } - copy( box ) { + let maxRadiusSq = 0; - this.min.copy( box.min ); - this.max.copy( box.max ); + for ( let i = 0, il = points.length; i < il; i ++ ) { + + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + + } + + this.radius = Math.sqrt( maxRadiusSq ); return this; } - makeEmpty() { + copy( sphere ) { - this.min.x = this.min.y = this.min.z = + Infinity; - this.max.x = this.max.y = this.max.z = - Infinity; + this.center.copy( sphere.center ); + this.radius = sphere.radius; return this; @@ -4733,1205 +5029,1271 @@ isEmpty() { - // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes - - return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); + return ( this.radius < 0 ); } - getCenter( target ) { + makeEmpty() { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); + this.center.set( 0, 0, 0 ); + this.radius = - 1; + + return this; } - getSize( target ) { + containsPoint( point ) { - return this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min ); + return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); } - expandByPoint( point ) { - - this.min.min( point ); - this.max.max( point ); + distanceToPoint( point ) { - return this; + return ( point.distanceTo( this.center ) - this.radius ); } - expandByVector( vector ) { + intersectsSphere( sphere ) { - this.min.sub( vector ); - this.max.add( vector ); + const radiusSum = this.radius + sphere.radius; - return this; + return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); } - expandByScalar( scalar ) { + intersectsBox( box ) { - this.min.addScalar( - scalar ); - this.max.addScalar( scalar ); + return box.intersectsSphere( this ); - return this; + } + + intersectsPlane( plane ) { + + return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; } - expandByObject( object, precise = false ) { + clampPoint( point, target ) { - // Computes the world-axis-aligned bounding box of an object (including its children), - // accounting for both the object's, and children's, world transforms + const deltaLengthSq = this.center.distanceToSquared( point ); - object.updateWorldMatrix( false, false ); + target.copy( point ); - const geometry = object.geometry; + if ( deltaLengthSq > ( this.radius * this.radius ) ) { - if ( geometry !== undefined ) { + target.sub( this.center ).normalize(); + target.multiplyScalar( this.radius ).add( this.center ); - if ( precise && geometry.attributes != undefined && geometry.attributes.position !== undefined ) { + } - const position = geometry.attributes.position; - for ( let i = 0, l = position.count; i < l; i ++ ) { + return target; - _vector$b.fromBufferAttribute( position, i ).applyMatrix4( object.matrixWorld ); - this.expandByPoint( _vector$b ); + } - } + getBoundingBox( target ) { - } else { + if ( this.isEmpty() ) { - if ( geometry.boundingBox === null ) { + // Empty sphere produces empty bounding box + target.makeEmpty(); + return target; - geometry.computeBoundingBox(); + } - } + target.set( this.center, this.center ); + target.expandByScalar( this.radius ); - _box$3.copy( geometry.boundingBox ); - _box$3.applyMatrix4( object.matrixWorld ); + return target; - this.union( _box$3 ); + } - } + applyMatrix4( matrix ) { - } + this.center.applyMatrix4( matrix ); + this.radius = this.radius * matrix.getMaxScaleOnAxis(); - const children = object.children; + return this; - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - this.expandByObject( children[ i ], precise ); + translate( offset ) { - } + this.center.add( offset ); return this; } - containsPoint( point ) { + expandByPoint( point ) { - return point.x < this.min.x || point.x > this.max.x || - point.y < this.min.y || point.y > this.max.y || - point.z < this.min.z || point.z > this.max.z ? false : true; + if ( this.isEmpty() ) { - } + this.center.copy( point ); - containsBox( box ) { + this.radius = 0; - return this.min.x <= box.min.x && box.max.x <= this.max.x && - this.min.y <= box.min.y && box.max.y <= this.max.y && - this.min.z <= box.min.z && box.max.z <= this.max.z; + return this; - } + } - getParameter( point, target ) { + _v1$6.subVectors( point, this.center ); - // This can potentially have a divide by zero if the box - // has a size dimension of 0. + const lengthSq = _v1$6.lengthSq(); - 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 ) - ); + if ( lengthSq > ( this.radius * this.radius ) ) { - } + // calculate the minimal sphere - intersectsBox( box ) { + const length = Math.sqrt( lengthSq ); - // using 6 splitting planes to rule out intersections. - return box.max.x < this.min.x || box.min.x > this.max.x || - box.max.y < this.min.y || box.min.y > this.max.y || - box.max.z < this.min.z || box.min.z > this.max.z ? false : true; + const delta = ( length - this.radius ) * 0.5; - } + this.center.addScaledVector( _v1$6, delta / length ); - intersectsSphere( sphere ) { + this.radius += delta; - // 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 ); + return this; } - intersectsPlane( plane ) { + union( sphere ) { - // We compute the minimum and maximum dot product values. If those values - // are on the same side (back or front) of the plane, then there is no intersection. + if ( sphere.isEmpty() ) { - let min, max; + return this; - if ( plane.normal.x > 0 ) { + } - min = plane.normal.x * this.min.x; - max = plane.normal.x * this.max.x; + if ( this.isEmpty() ) { - } else { + this.copy( sphere ); - min = plane.normal.x * this.max.x; - max = plane.normal.x * this.min.x; + return this; } - if ( plane.normal.y > 0 ) { + if ( this.center.equals( sphere.center ) === true ) { - min += plane.normal.y * this.min.y; - max += plane.normal.y * this.max.y; + this.radius = Math.max( this.radius, sphere.radius ); } else { - min += plane.normal.y * this.max.y; - max += plane.normal.y * this.min.y; - - } - - if ( plane.normal.z > 0 ) { - - min += plane.normal.z * this.min.z; - max += plane.normal.z * this.max.z; + _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); - } else { + this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); - min += plane.normal.z * this.max.z; - max += plane.normal.z * this.min.z; + this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); } - return ( min <= - plane.constant && max >= - plane.constant ); + return this; } - intersectsTriangle( triangle ) { - - if ( this.isEmpty() ) { - - return false; - - } + equals( sphere ) { - // compute box center and extents - this.getCenter( _center ); - _extents.subVectors( this.max, _center ); + return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); - // translate triangle to aabb origin - _v0$2.subVectors( triangle.a, _center ); - _v1$7.subVectors( triangle.b, _center ); - _v2$4.subVectors( triangle.c, _center ); + } - // compute edge vectors for triangle - _f0.subVectors( _v1$7, _v0$2 ); - _f1.subVectors( _v2$4, _v1$7 ); - _f2.subVectors( _v0$2, _v2$4 ); + clone() { - // test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb - // make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation - // axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned) - let axes = [ - 0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y, - _f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x, - - _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0 - ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + return new this.constructor().copy( this ); - return false; + } - } + } - // test 3 face normals from the aabb - axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]; - if ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) { + const _vector$a = /*@__PURE__*/ new Vector3(); + const _segCenter = /*@__PURE__*/ new Vector3(); + const _segDir = /*@__PURE__*/ new Vector3(); + const _diff = /*@__PURE__*/ new Vector3(); - return false; + const _edge1 = /*@__PURE__*/ new Vector3(); + const _edge2 = /*@__PURE__*/ new Vector3(); + const _normal$1 = /*@__PURE__*/ new Vector3(); - } + class Ray { - // finally testing the face normal of the triangle - // use already existing triangle edge vectors here - _triangleNormal.crossVectors( _f0, _f1 ); - axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ]; + constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { - return satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ); + this.origin = origin; + this.direction = direction; } - clampPoint( point, target ) { + set( origin, direction ) { - return target.copy( point ).clamp( this.min, this.max ); + this.origin.copy( origin ); + this.direction.copy( direction ); + + return this; } - distanceToPoint( point ) { + copy( ray ) { - const clampedPoint = _vector$b.copy( point ).clamp( this.min, this.max ); + this.origin.copy( ray.origin ); + this.direction.copy( ray.direction ); - return clampedPoint.sub( point ).length(); + return this; } - getBoundingSphere( target ) { - - this.getCenter( target.center ); - - target.radius = this.getSize( _vector$b ).length() * 0.5; + at( t, target ) { - return target; + return target.copy( this.origin ).addScaledVector( this.direction, t ); } - intersect( box ) { - - this.min.max( box.min ); - this.max.min( box.max ); + lookAt( v ) { - // ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values. - if ( this.isEmpty() ) this.makeEmpty(); + this.direction.copy( v ).sub( this.origin ).normalize(); return this; } - union( box ) { + recast( t ) { - this.min.min( box.min ); - this.max.max( box.max ); + this.origin.copy( this.at( t, _vector$a ) ); return this; } - applyMatrix4( matrix ) { - - // transform of empty box is an empty box. - if ( this.isEmpty() ) return this; - - // NOTE: I am using a binary pattern to specify all 2^3 combinations below - _points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 - _points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 - _points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 - _points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 - _points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 - _points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 - _points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 - _points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 + closestPointToPoint( point, target ) { - this.setFromPoints( _points ); + target.subVectors( point, this.origin ); - return this; + const directionDistance = target.dot( this.direction ); - } + if ( directionDistance < 0 ) { - translate( offset ) { + return target.copy( this.origin ); - this.min.add( offset ); - this.max.add( offset ); + } - return this; + return target.copy( this.origin ).addScaledVector( this.direction, directionDistance ); } - equals( box ) { + distanceToPoint( point ) { - return box.min.equals( this.min ) && box.max.equals( this.max ); + return Math.sqrt( this.distanceSqToPoint( point ) ); } - } + distanceSqToPoint( point ) { - 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() - ]; + const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); - const _vector$b = /*@__PURE__*/ new Vector3(); + // point behind the ray - const _box$3 = /*@__PURE__*/ new Box3(); + if ( directionDistance < 0 ) { - // triangle centered vertices + return this.origin.distanceToSquared( point ); - const _v0$2 = /*@__PURE__*/ new Vector3(); - const _v1$7 = /*@__PURE__*/ new Vector3(); - const _v2$4 = /*@__PURE__*/ new Vector3(); + } - // triangle edge vectors + _vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance ); - const _f0 = /*@__PURE__*/ new Vector3(); - const _f1 = /*@__PURE__*/ new Vector3(); - const _f2 = /*@__PURE__*/ new Vector3(); + return _vector$a.distanceToSquared( point ); - const _center = /*@__PURE__*/ new Vector3(); - const _extents = /*@__PURE__*/ new Vector3(); - const _triangleNormal = /*@__PURE__*/ new Vector3(); - const _testAxis = /*@__PURE__*/ new Vector3(); + } - function satForAxes( axes, v0, v1, v2, extents ) { + distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - for ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) { + // 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 - _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 ) { + _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); + _segDir.copy( v1 ).sub( v0 ).normalize(); + _diff.copy( this.origin ).sub( _segCenter ); - // points of the projected triangle are outside the projected half-length of the aabb - // the axis is separating and we can exit - return false; - - } + const segExtent = v0.distanceTo( v1 ) * 0.5; + const a01 = - this.direction.dot( _segDir ); + const b0 = _diff.dot( this.direction ); + const b1 = - _diff.dot( _segDir ); + const c = _diff.lengthSq(); + const det = Math.abs( 1 - a01 * a01 ); + let s0, s1, sqrDist, extDet; - } + if ( det > 0 ) { - return true; + // The ray and segment are not parallel. - } + s0 = a01 * b1 - b0; + s1 = a01 * b0 - b1; + extDet = segExtent * det; - const _box$2 = /*@__PURE__*/ new Box3(); - const _v1$6 = /*@__PURE__*/ new Vector3(); - const _v2$3 = /*@__PURE__*/ new Vector3(); + if ( s0 >= 0 ) { - class Sphere { + if ( s1 >= - extDet ) { - constructor( center = new Vector3(), radius = - 1 ) { + if ( s1 <= extDet ) { - this.center = center; - this.radius = radius; + // region 0 + // Minimum at interior points of ray and segment. - } + const invDet = 1 / det; + s0 *= invDet; + s1 *= invDet; + sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; - set( center, radius ) { + } else { - this.center.copy( center ); - this.radius = radius; + // region 1 - return this; + s1 = segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - } + } - setFromPoints( points, optionalCenter ) { + } else { - const center = this.center; + // region 5 - if ( optionalCenter !== undefined ) { + s1 = - segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - center.copy( optionalCenter ); + } - } else { + } else { - _box$2.setFromPoints( points ).getCenter( center ); + if ( s1 <= - extDet ) { - } + // region 4 - let maxRadiusSq = 0; + s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - for ( let i = 0, il = points.length; i < il; i ++ ) { + } else if ( s1 <= extDet ) { - maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); + // region 3 - } + s0 = 0; + s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = s1 * ( s1 + 2 * b1 ) + c; - this.radius = Math.sqrt( maxRadiusSq ); + } else { - return this; + // region 2 - } + s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); + s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - copy( sphere ) { + } - this.center.copy( sphere.center ); - this.radius = sphere.radius; + } - return this; + } else { - } + // Ray and segment are parallel. - isEmpty() { + s1 = ( a01 > 0 ) ? - segExtent : segExtent; + s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); + sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; - return ( this.radius < 0 ); + } - } + if ( optionalPointOnRay ) { - makeEmpty() { + optionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 ); - this.center.set( 0, 0, 0 ); - this.radius = - 1; + } - return this; + if ( optionalPointOnSegment ) { - } + optionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 ); - containsPoint( point ) { + } - return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); + return sqrDist; } - distanceToPoint( point ) { + intersectSphere( sphere, target ) { - return ( point.distanceTo( this.center ) - this.radius ); + _vector$a.subVectors( sphere.center, this.origin ); + const tca = _vector$a.dot( this.direction ); + const d2 = _vector$a.dot( _vector$a ) - tca * tca; + const radius2 = sphere.radius * sphere.radius; - } + if ( d2 > radius2 ) return null; - intersectsSphere( sphere ) { + const thc = Math.sqrt( radius2 - d2 ); - const radiusSum = this.radius + sphere.radius; + // t0 = first intersect point - entrance on front of sphere + const t0 = tca - thc; - return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); + // t1 = second intersect point - exit point on back of sphere + const t1 = tca + thc; - } + // test to see if t1 is behind the ray - if so, return null + if ( t1 < 0 ) return null; - intersectsBox( box ) { + // test to see if t0 is behind the ray: + // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, + // in order to always return an intersect point that is in front of the ray. + if ( t0 < 0 ) return this.at( t1, target ); - return box.intersectsSphere( this ); + // else t0 is in front of the ray, so return the first collision point scaled by t0 + return this.at( t0, target ); } - intersectsPlane( plane ) { + intersectsSphere( sphere ) { - return Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius; + return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); } - clampPoint( point, target ) { - - const deltaLengthSq = this.center.distanceToSquared( point ); - - target.copy( point ); - - if ( deltaLengthSq > ( this.radius * this.radius ) ) { + distanceToPlane( plane ) { - target.sub( this.center ).normalize(); - target.multiplyScalar( this.radius ).add( this.center ); + const denominator = plane.normal.dot( this.direction ); - } + if ( denominator === 0 ) { - return target; + // line is coplanar, return origin + if ( plane.distanceToPoint( this.origin ) === 0 ) { - } + return 0; - getBoundingBox( target ) { + } - if ( this.isEmpty() ) { + // Null is preferable to undefined since undefined means.... it is undefined - // Empty sphere produces empty bounding box - target.makeEmpty(); - return target; + return null; } - target.set( this.center, this.center ); - target.expandByScalar( this.radius ); + const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; - return target; + // Return if the ray never intersects the plane - } + return t >= 0 ? t : null; - applyMatrix4( matrix ) { + } - this.center.applyMatrix4( matrix ); - this.radius = this.radius * matrix.getMaxScaleOnAxis(); + intersectPlane( plane, target ) { - return this; + const t = this.distanceToPlane( plane ); - } + if ( t === null ) { - translate( offset ) { + return null; - this.center.add( offset ); + } - return this; + return this.at( t, target ); } - expandByPoint( point ) { + intersectsPlane( plane ) { - if ( this.isEmpty() ) { + // check if the ray lies on the plane first - this.center.copy( point ); + const distToPoint = plane.distanceToPoint( this.origin ); - this.radius = 0; + if ( distToPoint === 0 ) { - return this; + return true; } - _v1$6.subVectors( point, this.center ); + const denominator = plane.normal.dot( this.direction ); - const lengthSq = _v1$6.lengthSq(); + if ( denominator * distToPoint < 0 ) { - if ( lengthSq > ( this.radius * this.radius ) ) { + return true; - // calculate the minimal sphere + } - const length = Math.sqrt( lengthSq ); + // ray origin is behind the plane (and is pointing behind it) - const delta = ( length - this.radius ) * 0.5; + return false; - this.center.addScaledVector( _v1$6, delta / length ); + } - this.radius += delta; + intersectBox( box, target ) { - } + let tmin, tmax, tymin, tymax, tzmin, tzmax; - return this; + const invdirx = 1 / this.direction.x, + invdiry = 1 / this.direction.y, + invdirz = 1 / this.direction.z; - } + const origin = this.origin; - union( sphere ) { + if ( invdirx >= 0 ) { - if ( sphere.isEmpty() ) { + tmin = ( box.min.x - origin.x ) * invdirx; + tmax = ( box.max.x - origin.x ) * invdirx; - return this; + } else { + + tmin = ( box.max.x - origin.x ) * invdirx; + tmax = ( box.min.x - origin.x ) * invdirx; } - if ( this.isEmpty() ) { + if ( invdiry >= 0 ) { - this.copy( sphere ); + tymin = ( box.min.y - origin.y ) * invdiry; + tymax = ( box.max.y - origin.y ) * invdiry; - return this; + } else { + + tymin = ( box.max.y - origin.y ) * invdiry; + tymax = ( box.min.y - origin.y ) * invdiry; } - if ( this.center.equals( sphere.center ) === true ) { + if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; - this.radius = Math.max( this.radius, sphere.radius ); + if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; - } else { + if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; - _v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius ); + if ( invdirz >= 0 ) { - this.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) ); + tzmin = ( box.min.z - origin.z ) * invdirz; + tzmax = ( box.max.z - origin.z ) * invdirz; - this.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) ); + } else { - } + tzmin = ( box.max.z - origin.z ) * invdirz; + tzmax = ( box.min.z - origin.z ) * invdirz; - return this; + } - } + if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; - equals( sphere ) { + if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; - return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); + if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; - } + //return point closest to the ray (positive side) - clone() { + if ( tmax < 0 ) return null; - return new this.constructor().copy( this ); + return this.at( tmin >= 0 ? tmin : tmax, target ); } - } - - const _vector$a = /*@__PURE__*/ new Vector3(); - const _segCenter = /*@__PURE__*/ new Vector3(); - const _segDir = /*@__PURE__*/ new Vector3(); - const _diff = /*@__PURE__*/ new Vector3(); - - const _edge1 = /*@__PURE__*/ new Vector3(); - const _edge2 = /*@__PURE__*/ new Vector3(); - const _normal$1 = /*@__PURE__*/ new Vector3(); + intersectsBox( box ) { - class Ray { + return this.intersectBox( box, _vector$a ) !== null; - constructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) { + } - this.origin = origin; - this.direction = direction; + intersectTriangle( a, b, c, backfaceCulling, target ) { - } + // Compute the offset origin, edges, and normal. - set( origin, direction ) { + // from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h - this.origin.copy( origin ); - this.direction.copy( direction ); + _edge1.subVectors( b, a ); + _edge2.subVectors( c, a ); + _normal$1.crossVectors( _edge1, _edge2 ); - return this; + // 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 ) { - copy( ray ) { + if ( backfaceCulling ) return null; + sign = 1; - this.origin.copy( ray.origin ); - this.direction.copy( ray.direction ); + } else if ( DdN < 0 ) { - return this; + sign = - 1; + DdN = - DdN; - } + } else { - at( t, target ) { + return null; - return target.copy( this.direction ).multiplyScalar( t ).add( this.origin ); + } - } + _diff.subVectors( this.origin, a ); + const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); - lookAt( v ) { + // b1 < 0, no intersection + if ( DdQxE2 < 0 ) { - this.direction.copy( v ).sub( this.origin ).normalize(); + return null; - return this; + } - } + const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); - recast( t ) { + // b2 < 0, no intersection + if ( DdE1xQ < 0 ) { - this.origin.copy( this.at( t, _vector$a ) ); + return null; - return this; + } - } + // b1+b2 > 1, no intersection + if ( DdQxE2 + DdE1xQ > DdN ) { - closestPointToPoint( point, target ) { + return null; - target.subVectors( point, this.origin ); + } - const directionDistance = target.dot( this.direction ); + // Line intersects triangle, check if ray does. + const QdN = - sign * _diff.dot( _normal$1 ); - if ( directionDistance < 0 ) { + // t < 0, no intersection + if ( QdN < 0 ) { - return target.copy( this.origin ); + return null; } - return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + // Ray intersects triangle. + return this.at( QdN / DdN, target ); } - distanceToPoint( point ) { - - return Math.sqrt( this.distanceSqToPoint( point ) ); - - } + applyMatrix4( matrix4 ) { - distanceSqToPoint( point ) { + this.origin.applyMatrix4( matrix4 ); + this.direction.transformDirection( matrix4 ); - const directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction ); + return this; - // point behind the ray + } - if ( directionDistance < 0 ) { + equals( ray ) { - return this.origin.distanceToSquared( point ); + return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); - } + } - _vector$a.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); + clone() { - return _vector$a.distanceToSquared( point ); + return new this.constructor().copy( this ); } - distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { - - // 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 - - _segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 ); - _segDir.copy( v1 ).sub( v0 ).normalize(); - _diff.copy( this.origin ).sub( _segCenter ); + } - const segExtent = v0.distanceTo( v1 ) * 0.5; - const a01 = - this.direction.dot( _segDir ); - const b0 = _diff.dot( this.direction ); - const b1 = - _diff.dot( _segDir ); - const c = _diff.lengthSq(); - const det = Math.abs( 1 - a01 * a01 ); - let s0, s1, sqrDist, extDet; + class Matrix4 { - if ( det > 0 ) { + constructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - // The ray and segment are not parallel. + Matrix4.prototype.isMatrix4 = true; - s0 = a01 * b1 - b0; - s1 = a01 * b0 - b1; - extDet = segExtent * det; + this.elements = [ - if ( s0 >= 0 ) { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 >= - extDet ) { + ]; - if ( s1 <= extDet ) { + if ( n11 !== undefined ) { - // region 0 - // Minimum at interior points of ray and segment. + this.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ); - const invDet = 1 / det; - s0 *= invDet; - s1 *= invDet; - sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; + } - } else { + } - // region 1 + set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { - s1 = segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + const te = this.elements; - } + te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; + te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; + te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; + te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; - } else { + return this; - // region 5 + } - s1 = - segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + identity() { - } + this.set( - } else { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 - if ( s1 <= - extDet ) { + ); - // region 4 + return this; - s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + } - } else if ( s1 <= extDet ) { + clone() { - // region 3 + return new Matrix4().fromArray( this.elements ); - s0 = 0; - s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = s1 * ( s1 + 2 * b1 ) + c; + } - } else { + copy( m ) { - // region 2 + const te = this.elements; + const me = m.elements; - s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); - s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; + te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; + te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; + te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; - } + return this; - } + } - } else { + copyPosition( m ) { - // Ray and segment are parallel. + const te = this.elements, me = m.elements; - s1 = ( a01 > 0 ) ? - segExtent : segExtent; - s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); - sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; + te[ 12 ] = me[ 12 ]; + te[ 13 ] = me[ 13 ]; + te[ 14 ] = me[ 14 ]; - } + return this; - if ( optionalPointOnRay ) { + } - optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin ); + setFromMatrix3( m ) { - } + const me = m.elements; - if ( optionalPointOnSegment ) { + this.set( - optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter ); + me[ 0 ], me[ 3 ], me[ 6 ], 0, + me[ 1 ], me[ 4 ], me[ 7 ], 0, + me[ 2 ], me[ 5 ], me[ 8 ], 0, + 0, 0, 0, 1 - } + ); - return sqrDist; + return this; } - intersectSphere( sphere, target ) { + extractBasis( xAxis, yAxis, zAxis ) { - _vector$a.subVectors( sphere.center, this.origin ); - const tca = _vector$a.dot( this.direction ); - const d2 = _vector$a.dot( _vector$a ) - tca * tca; - const radius2 = sphere.radius * sphere.radius; + xAxis.setFromMatrixColumn( this, 0 ); + yAxis.setFromMatrixColumn( this, 1 ); + zAxis.setFromMatrixColumn( this, 2 ); - if ( d2 > radius2 ) return null; + return this; - const thc = Math.sqrt( radius2 - d2 ); + } - // t0 = first intersect point - entrance on front of sphere - const t0 = tca - thc; + makeBasis( xAxis, yAxis, zAxis ) { - // t1 = second intersect point - exit point on back of sphere - const t1 = tca + thc; + 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 + ); - // test to see if both t0 and t1 are behind the ray - if so, return null - if ( t0 < 0 && t1 < 0 ) return null; + return this; - // test to see if t0 is behind the ray: - // if it is, the ray is inside the sphere, so return the second exit point scaled by t1, - // in order to always return an intersect point that is in front of the ray. - if ( t0 < 0 ) return this.at( t1, target ); + } - // else t0 is in front of the ray, so return the first collision point scaled by t0 - return this.at( t0, target ); + extractRotation( m ) { - } + // this method does not support reflection matrices - intersectsSphere( sphere ) { + const te = this.elements; + const me = m.elements; - return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius ); + const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); + const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); + const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + + te[ 0 ] = me[ 0 ] * scaleX; + te[ 1 ] = me[ 1 ] * scaleX; + te[ 2 ] = me[ 2 ] * scaleX; + te[ 3 ] = 0; + + te[ 4 ] = me[ 4 ] * scaleY; + te[ 5 ] = me[ 5 ] * scaleY; + te[ 6 ] = me[ 6 ] * scaleY; + te[ 7 ] = 0; + + te[ 8 ] = me[ 8 ] * scaleZ; + te[ 9 ] = me[ 9 ] * scaleZ; + te[ 10 ] = me[ 10 ] * scaleZ; + te[ 11 ] = 0; + + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; + + return this; } - distanceToPlane( plane ) { + makeRotationFromEuler( euler ) { - const denominator = plane.normal.dot( this.direction ); + const te = this.elements; - if ( denominator === 0 ) { + const x = euler.x, y = euler.y, z = euler.z; + const a = Math.cos( x ), b = Math.sin( x ); + const c = Math.cos( y ), d = Math.sin( y ); + const e = Math.cos( z ), f = Math.sin( z ); - // line is coplanar, return origin - if ( plane.distanceToPoint( this.origin ) === 0 ) { + if ( euler.order === 'XYZ' ) { - return 0; + const ae = a * e, af = a * f, be = b * e, bf = b * f; - } + te[ 0 ] = c * e; + te[ 4 ] = - c * f; + te[ 8 ] = d; - // Null is preferable to undefined since undefined means.... it is undefined + te[ 1 ] = af + be * d; + te[ 5 ] = ae - bf * d; + te[ 9 ] = - b * c; - return null; + te[ 2 ] = bf - ae * d; + te[ 6 ] = be + af * d; + te[ 10 ] = a * c; - } + } else if ( euler.order === 'YXZ' ) { - const t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; + const ce = c * e, cf = c * f, de = d * e, df = d * f; - // Return if the ray never intersects the plane + te[ 0 ] = ce + df * b; + te[ 4 ] = de * b - cf; + te[ 8 ] = a * d; - return t >= 0 ? t : null; + 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; - intersectPlane( plane, target ) { + } else if ( euler.order === 'ZXY' ) { - const t = this.distanceToPlane( plane ); + const ce = c * e, cf = c * f, de = d * e, df = d * f; - if ( t === null ) { + te[ 0 ] = ce - df * b; + te[ 4 ] = - a * f; + te[ 8 ] = de + cf * b; - return null; + 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; - return this.at( t, target ); + } else if ( euler.order === 'ZYX' ) { - } + const ae = a * e, af = a * f, be = b * e, bf = b * f; - intersectsPlane( plane ) { + te[ 0 ] = c * e; + te[ 4 ] = be * d - af; + te[ 8 ] = ae * d + bf; - // check if the ray lies on the plane first + te[ 1 ] = c * f; + te[ 5 ] = bf * d + ae; + te[ 9 ] = af * d - be; - const distToPoint = plane.distanceToPoint( this.origin ); + te[ 2 ] = - d; + te[ 6 ] = b * c; + te[ 10 ] = a * c; - if ( distToPoint === 0 ) { + } else if ( euler.order === 'YZX' ) { - return true; + 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; - const denominator = plane.normal.dot( this.direction ); + te[ 1 ] = f; + te[ 5 ] = a * e; + te[ 9 ] = - b * e; - if ( denominator * distToPoint < 0 ) { + te[ 2 ] = - d * e; + te[ 6 ] = ad * f + bc; + te[ 10 ] = ac - bd * f; - return true; + } else if ( euler.order === 'XZY' ) { - } + const ac = a * c, ad = a * d, bc = b * c, bd = b * d; - // ray origin is behind the plane (and is pointing behind it) + te[ 0 ] = c * e; + te[ 4 ] = - f; + te[ 8 ] = d * e; - return false; + 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; - intersectBox( box, target ) { + } - let tmin, tmax, tymin, tymax, tzmin, tzmax; + // bottom row + te[ 3 ] = 0; + te[ 7 ] = 0; + te[ 11 ] = 0; - const invdirx = 1 / this.direction.x, - invdiry = 1 / this.direction.y, - invdirz = 1 / this.direction.z; + // last column + te[ 12 ] = 0; + te[ 13 ] = 0; + te[ 14 ] = 0; + te[ 15 ] = 1; - const origin = this.origin; + return this; - if ( invdirx >= 0 ) { + } - tmin = ( box.min.x - origin.x ) * invdirx; - tmax = ( box.max.x - origin.x ) * invdirx; + makeRotationFromQuaternion( q ) { - } else { + return this.compose( _zero, q, _one ); - tmin = ( box.max.x - origin.x ) * invdirx; - tmax = ( box.min.x - origin.x ) * invdirx; + } - } + lookAt( eye, target, up ) { - if ( invdiry >= 0 ) { + const te = this.elements; - tymin = ( box.min.y - origin.y ) * invdiry; - tymax = ( box.max.y - origin.y ) * invdiry; + _z.subVectors( eye, target ); - } else { + if ( _z.lengthSq() === 0 ) { - tymin = ( box.max.y - origin.y ) * invdiry; - tymax = ( box.min.y - origin.y ) * invdiry; + // eye and target are in the same position - } + _z.z = 1; - if ( ( tmin > tymax ) || ( tymin > tmax ) ) return null; + } - if ( tymin > tmin || isNaN( tmin ) ) tmin = tymin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tymax < tmax || isNaN( tmax ) ) tmax = tymax; + if ( _x.lengthSq() === 0 ) { - if ( invdirz >= 0 ) { + // up and z are parallel - tzmin = ( box.min.z - origin.z ) * invdirz; - tzmax = ( box.max.z - origin.z ) * invdirz; + if ( Math.abs( up.z ) === 1 ) { - } else { + _z.x += 0.0001; - tzmin = ( box.max.z - origin.z ) * invdirz; - tzmax = ( box.min.z - origin.z ) * invdirz; + } else { - } + _z.z += 0.0001; - if ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null; + } - if ( tzmin > tmin || tmin !== tmin ) tmin = tzmin; + _z.normalize(); + _x.crossVectors( up, _z ); - if ( tzmax < tmax || tmax !== tmax ) tmax = tzmax; + } - //return point closest to the ray (positive side) + _x.normalize(); + _y.crossVectors( _z, _x ); - if ( tmax < 0 ) return null; + te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; + te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; + te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; - return this.at( tmin >= 0 ? tmin : tmax, target ); + return this; } - intersectsBox( box ) { + multiply( m ) { - return this.intersectBox( box, _vector$a ) !== null; + return this.multiplyMatrices( this, m ); } - intersectTriangle( a, b, c, backfaceCulling, target ) { + premultiply( m ) { - // Compute the offset origin, edges, and normal. + return this.multiplyMatrices( m, this ); - // 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 ) { + multiplyMatrices( a, b ) { - if ( backfaceCulling ) return null; - sign = 1; + const ae = a.elements; + const be = b.elements; + const te = this.elements; - } else if ( DdN < 0 ) { + const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; + const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; + const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; + const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; - sign = - 1; - DdN = - DdN; + const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; + const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; + const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; + const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; - } else { + te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; + te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; + te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; + te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; - return null; + te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; + te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; + te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; + te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; - } + te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; + te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; + te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; + te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; - _diff.subVectors( this.origin, a ); - const DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) ); + te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; + te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; + te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; + te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; - // b1 < 0, no intersection - if ( DdQxE2 < 0 ) { + return this; - return null; + } - } + multiplyScalar( s ) { - const DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) ); + const te = this.elements; - // b2 < 0, no intersection - if ( DdE1xQ < 0 ) { + te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; + te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; + te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; + te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; - return null; + return this; - } + } - // b1+b2 > 1, no intersection - if ( DdQxE2 + DdE1xQ > DdN ) { + determinant() { - return null; + const te = this.elements; - } + const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; + const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; + const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; + const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; - // Line intersects triangle, check if ray does. - const QdN = - sign * _diff.dot( _normal$1 ); + //TODO: make this more efficient + //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) - // t < 0, no intersection - if ( QdN < 0 ) { + 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 + ) - return null; + ); - } + } - // Ray intersects triangle. - return this.at( QdN / DdN, target ); + transpose() { - } + const te = this.elements; + let tmp; - applyMatrix4( matrix4 ) { + tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; + tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; + tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; - this.origin.applyMatrix4( matrix4 ); - this.direction.transformDirection( matrix4 ); + tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; + tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; + tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; return this; } - equals( ray ) { + setPosition( x, y, z ) { - return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); + const te = this.elements; - } + if ( x.isVector3 ) { - clone() { + te[ 12 ] = x.x; + te[ 13 ] = x.y; + te[ 14 ] = x.z; - return new this.constructor().copy( this ); + } else { + + te[ 12 ] = x; + te[ 13 ] = y; + te[ 14 ] = z; + + } + + return this; } - } + invert() { - class Matrix4 { + // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm + const te = this.elements, - constructor() { + n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], + n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], + n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], + n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], - Matrix4.prototype.isMatrix4 = true; + 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; - this.elements = [ + const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); - ]; + const detInv = 1 / det; - } + te[ 0 ] = t11 * detInv; + te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; + te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; + te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; - set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { + te[ 4 ] = t12 * detInv; + te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; + te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; + te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; - const te = this.elements; + te[ 8 ] = t13 * detInv; + te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; + te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; + te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; - te[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14; - te[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24; - te[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34; - te[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44; + te[ 12 ] = t14 * detInv; + te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; + te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; + te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; return this; } - identity() { - - this.set( + scale( v ) { - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + const te = this.elements; + const x = v.x, y = v.y, z = v.z; - ); + te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; + te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; + te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; + te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; return this; } - clone() { + getMaxScaleOnAxis() { - return new Matrix4().fromArray( this.elements ); + const te = this.elements; + + const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; + const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; + const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + + return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); } - copy( m ) { + makeTranslation( x, y, z ) { - const te = this.elements; - const me = m.elements; + if ( x.isVector3 ) { - te[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ]; - te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; - te[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ]; - te[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ]; + this.set( - return this; + 1, 0, 0, x.x, + 0, 1, 0, x.y, + 0, 0, 1, x.z, + 0, 0, 0, 1 - } + ); - copyPosition( m ) { + } else { - const te = this.elements, me = m.elements; + this.set( - te[ 12 ] = me[ 12 ]; - te[ 13 ] = me[ 13 ]; - te[ 14 ] = me[ 14 ]; + 1, 0, 0, x, + 0, 1, 0, y, + 0, 0, 1, z, + 0, 0, 0, 1 + + ); + + } return this; } - setFromMatrix3( m ) { + makeRotationX( theta ) { - const me = m.elements; + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - me[ 0 ], me[ 3 ], me[ 6 ], 0, - me[ 1 ], me[ 4 ], me[ 7 ], 0, - me[ 2 ], me[ 5 ], me[ 8 ], 0, + 1, 0, 0, 0, + 0, c, - s, 0, + 0, s, c, 0, 0, 0, 0, 1 ); @@ -5940,2377 +6302,2635 @@ } - extractBasis( xAxis, yAxis, zAxis ) { + makeRotationY( theta ) { - xAxis.setFromMatrixColumn( this, 0 ); - yAxis.setFromMatrixColumn( this, 1 ); - zAxis.setFromMatrixColumn( this, 2 ); + const c = Math.cos( theta ), s = Math.sin( theta ); + + this.set( + + c, 0, s, 0, + 0, 1, 0, 0, + - s, 0, c, 0, + 0, 0, 0, 1 + + ); return this; } - makeBasis( xAxis, yAxis, zAxis ) { + makeRotationZ( theta ) { + + const c = Math.cos( theta ), s = Math.sin( theta ); this.set( - xAxis.x, yAxis.x, zAxis.x, 0, - xAxis.y, yAxis.y, zAxis.y, 0, - xAxis.z, yAxis.z, zAxis.z, 0, + + c, - s, 0, 0, + s, c, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 1 + ); return this; } - extractRotation( m ) { - - // this method does not support reflection matrices - - const te = this.elements; - const me = m.elements; + makeRotationAxis( axis, angle ) { - const scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length(); - const scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length(); - const scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length(); + // Based on http://www.gamedev.net/reference/articles/article1199.asp - te[ 0 ] = me[ 0 ] * scaleX; - te[ 1 ] = me[ 1 ] * scaleX; - te[ 2 ] = me[ 2 ] * scaleX; - te[ 3 ] = 0; + const c = Math.cos( angle ); + const s = Math.sin( angle ); + const t = 1 - c; + const x = axis.x, y = axis.y, z = axis.z; + const tx = t * x, ty = t * y; - te[ 4 ] = me[ 4 ] * scaleY; - te[ 5 ] = me[ 5 ] * scaleY; - te[ 6 ] = me[ 6 ] * scaleY; - te[ 7 ] = 0; + this.set( - te[ 8 ] = me[ 8 ] * scaleZ; - te[ 9 ] = me[ 9 ] * scaleZ; - te[ 10 ] = me[ 10 ] * scaleZ; - te[ 11 ] = 0; + 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 - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + ); return this; } - makeRotationFromEuler( euler ) { - - const te = this.elements; - - const x = euler.x, y = euler.y, z = euler.z; - const a = Math.cos( x ), b = Math.sin( x ); - const c = Math.cos( y ), d = Math.sin( y ); - const e = Math.cos( z ), f = Math.sin( z ); + makeScale( x, y, z ) { - if ( euler.order === 'XYZ' ) { + this.set( - const ae = a * e, af = a * f, be = b * e, bf = b * f; + x, 0, 0, 0, + 0, y, 0, 0, + 0, 0, z, 0, + 0, 0, 0, 1 - 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; + return this; - te[ 2 ] = bf - ae * d; - te[ 6 ] = be + af * d; - te[ 10 ] = a * c; + } - } else if ( euler.order === 'YXZ' ) { + makeShear( xy, xz, yx, yz, zx, zy ) { - const ce = c * e, cf = c * f, de = d * e, df = d * f; + this.set( - te[ 0 ] = ce + df * b; - te[ 4 ] = de * b - cf; - te[ 8 ] = a * d; + 1, yx, zx, 0, + xy, 1, zy, 0, + xz, yz, 1, 0, + 0, 0, 0, 1 - 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; + return this; - } else if ( euler.order === 'ZXY' ) { + } - const ce = c * e, cf = c * f, de = d * e, df = d * f; + compose( position, quaternion, scale ) { - te[ 0 ] = ce - df * b; - te[ 4 ] = - a * f; - te[ 8 ] = de + cf * b; + const te = this.elements; - te[ 1 ] = cf + de * b; - te[ 5 ] = a * e; - te[ 9 ] = df - ce * b; + const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; + const x2 = x + x, y2 = y + y, z2 = z + z; + const xx = x * x2, xy = x * y2, xz = x * z2; + const yy = y * y2, yz = y * z2, zz = z * z2; + const wx = w * x2, wy = w * y2, wz = w * z2; - te[ 2 ] = - a * d; - te[ 6 ] = b; - te[ 10 ] = a * c; + const sx = scale.x, sy = scale.y, sz = scale.z; - } else if ( euler.order === 'ZYX' ) { + te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; + te[ 1 ] = ( xy + wz ) * sx; + te[ 2 ] = ( xz - wy ) * sx; + te[ 3 ] = 0; - const ae = a * e, af = a * f, be = b * e, bf = b * f; + te[ 4 ] = ( xy - wz ) * sy; + te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; + te[ 6 ] = ( yz + wx ) * sy; + te[ 7 ] = 0; - te[ 0 ] = c * e; - te[ 4 ] = be * d - af; - te[ 8 ] = ae * d + bf; + te[ 8 ] = ( xz + wy ) * sz; + te[ 9 ] = ( yz - wx ) * sz; + te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; + te[ 11 ] = 0; - te[ 1 ] = c * f; - te[ 5 ] = bf * d + ae; - te[ 9 ] = af * d - be; + te[ 12 ] = position.x; + te[ 13 ] = position.y; + te[ 14 ] = position.z; + te[ 15 ] = 1; - te[ 2 ] = - d; - te[ 6 ] = b * c; - te[ 10 ] = a * c; + return this; - } else if ( euler.order === 'YZX' ) { + } - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + decompose( position, quaternion, scale ) { - te[ 0 ] = c * e; - te[ 4 ] = bd - ac * f; - te[ 8 ] = bc * f + ad; + const te = this.elements; - te[ 1 ] = f; - te[ 5 ] = a * e; - te[ 9 ] = - b * e; + let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); + const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); + const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); - te[ 2 ] = - d * e; - te[ 6 ] = ad * f + bc; - te[ 10 ] = ac - bd * f; + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if ( det < 0 ) sx = - sx; - } else if ( euler.order === 'XZY' ) { + position.x = te[ 12 ]; + position.y = te[ 13 ]; + position.z = te[ 14 ]; - const ac = a * c, ad = a * d, bc = b * c, bd = b * d; + // scale the rotation part + _m1$2.copy( this ); - te[ 0 ] = c * e; - te[ 4 ] = - f; - te[ 8 ] = d * e; + const invSX = 1 / sx; + const invSY = 1 / sy; + const invSZ = 1 / sz; - te[ 1 ] = ac * f + bd; - te[ 5 ] = a * e; - te[ 9 ] = ad * f - bc; + _m1$2.elements[ 0 ] *= invSX; + _m1$2.elements[ 1 ] *= invSX; + _m1$2.elements[ 2 ] *= invSX; - te[ 2 ] = bc * f - ad; - te[ 6 ] = b * e; - te[ 10 ] = bd * f + ac; + _m1$2.elements[ 4 ] *= invSY; + _m1$2.elements[ 5 ] *= invSY; + _m1$2.elements[ 6 ] *= invSY; - } + _m1$2.elements[ 8 ] *= invSZ; + _m1$2.elements[ 9 ] *= invSZ; + _m1$2.elements[ 10 ] *= invSZ; - // bottom row - te[ 3 ] = 0; - te[ 7 ] = 0; - te[ 11 ] = 0; + quaternion.setFromRotationMatrix( _m1$2 ); - // last column - te[ 12 ] = 0; - te[ 13 ] = 0; - te[ 14 ] = 0; - te[ 15 ] = 1; + scale.x = sx; + scale.y = sy; + scale.z = sz; return this; } - makeRotationFromQuaternion( q ) { - - return this.compose( _zero, q, _one ); + makePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - } + const te = this.elements; + const x = 2 * near / ( right - left ); + const y = 2 * near / ( top - bottom ); - lookAt( eye, target, up ) { + const a = ( right + left ) / ( right - left ); + const b = ( top + bottom ) / ( top - bottom ); - const te = this.elements; + let c, d; - _z.subVectors( eye, target ); + if ( coordinateSystem === WebGLCoordinateSystem ) { - if ( _z.lengthSq() === 0 ) { + c = - ( far + near ) / ( far - near ); + d = ( - 2 * far * near ) / ( far - near ); - // eye and target are in the same position + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { - _z.z = 1; + c = - far / ( far - near ); + d = ( - far * near ) / ( far - near ); - } + } else { - _z.normalize(); - _x.crossVectors( up, _z ); + throw new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem ); - if ( _x.lengthSq() === 0 ) { + } - // up and z are parallel + te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; + te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; - if ( Math.abs( up.z ) === 1 ) { + return this; - _z.x += 0.0001; + } - } else { + makeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) { - _z.z += 0.0001; + const te = this.elements; + const w = 1.0 / ( right - left ); + const h = 1.0 / ( top - bottom ); + const p = 1.0 / ( far - near ); - } + const x = ( right + left ) * w; + const y = ( top + bottom ) * h; - _z.normalize(); - _x.crossVectors( up, _z ); + let z, zInv; - } + if ( coordinateSystem === WebGLCoordinateSystem ) { - _x.normalize(); - _y.crossVectors( _z, _x ); + z = ( far + near ) * p; + zInv = - 2 * p; - te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x; - te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y; - te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z; + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + z = near * p; + zInv = - 1 * p; + + } else { + + throw new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem ); + + } + + te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; + te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; + te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = zInv; te[ 14 ] = - z; + te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; return this; } - multiply( m ) { + equals( matrix ) { - return this.multiplyMatrices( this, m ); + const te = this.elements; + const me = matrix.elements; + + for ( let i = 0; i < 16; i ++ ) { + + if ( te[ i ] !== me[ i ] ) return false; + + } + + return true; } - premultiply( m ) { + fromArray( array, offset = 0 ) { - return this.multiplyMatrices( m, this ); + for ( let i = 0; i < 16; i ++ ) { + + this.elements[ i ] = array[ i + offset ]; + + } + + return this; } - multiplyMatrices( a, b ) { + toArray( array = [], offset = 0 ) { - const ae = a.elements; - const be = b.elements; const te = this.elements; - const a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ]; - const a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ]; - const a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ]; - const a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ]; + array[ offset ] = te[ 0 ]; + array[ offset + 1 ] = te[ 1 ]; + array[ offset + 2 ] = te[ 2 ]; + array[ offset + 3 ] = te[ 3 ]; - const b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ]; - const b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ]; - const b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ]; - const b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ]; + array[ offset + 4 ] = te[ 4 ]; + array[ offset + 5 ] = te[ 5 ]; + array[ offset + 6 ] = te[ 6 ]; + array[ offset + 7 ] = te[ 7 ]; - te[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; - te[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; - te[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; - te[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; + array[ offset + 8 ] = te[ 8 ]; + array[ offset + 9 ] = te[ 9 ]; + array[ offset + 10 ] = te[ 10 ]; + array[ offset + 11 ] = te[ 11 ]; - te[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; - te[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; - te[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; - te[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; + array[ offset + 12 ] = te[ 12 ]; + array[ offset + 13 ] = te[ 13 ]; + array[ offset + 14 ] = te[ 14 ]; + array[ offset + 15 ] = te[ 15 ]; - te[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; - te[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; - te[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; - te[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; + return array; - te[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; - te[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; - te[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; - te[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; + } - return this; + } - } + const _v1$5 = /*@__PURE__*/ new Vector3(); + const _m1$2 = /*@__PURE__*/ new Matrix4(); + const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); + const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); + const _x = /*@__PURE__*/ new Vector3(); + const _y = /*@__PURE__*/ new Vector3(); + const _z = /*@__PURE__*/ new Vector3(); - multiplyScalar( s ) { + const _matrix$1 = /*@__PURE__*/ new Matrix4(); + const _quaternion$3 = /*@__PURE__*/ new Quaternion(); - const te = this.elements; + class Euler { - te[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s; - te[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s; - te[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s; - te[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s; + constructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) { - return this; + this.isEuler = true; + + this._x = x; + this._y = y; + this._z = z; + this._order = order; } - determinant() { + get x() { - const te = this.elements; + return this._x; - const n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ]; - const n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ]; - const n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ]; - const n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ]; + } - //TODO: make this more efficient - //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) + set x( value ) { - 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 - ) + this._x = value; + this._onChangeCallback(); - ); + } + + get y() { + + return this._y; } - transpose() { + set y( value ) { - const te = this.elements; - let tmp; + this._y = value; + this._onChangeCallback(); - tmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp; - tmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp; - tmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp; + } - tmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp; - tmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp; - tmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp; + get z() { - return this; + return this._z; } - setPosition( x, y, z ) { + set z( value ) { - const te = this.elements; + this._z = value; + this._onChangeCallback(); - if ( x.isVector3 ) { + } - te[ 12 ] = x.x; - te[ 13 ] = x.y; - te[ 14 ] = x.z; + get order() { - } else { + return this._order; - te[ 12 ] = x; - te[ 13 ] = y; - te[ 14 ] = z; + } - } + set order( value ) { - return this; + this._order = value; + this._onChangeCallback(); } - invert() { + set( x, y, z, order = this._order ) { - // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm - const te = this.elements, + this._x = x; + this._y = y; + this._z = z; + this._order = order; - n11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ], - n12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ], - n13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ], - n14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ], + this._onChangeCallback(); - 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; + return this; - const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14; + } - if ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); + clone() { - const detInv = 1 / det; + return new this.constructor( this._x, this._y, this._z, this._order ); - te[ 0 ] = t11 * detInv; - te[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv; - te[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv; - te[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv; + } - te[ 4 ] = t12 * detInv; - te[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv; - te[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv; - te[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv; + copy( euler ) { - te[ 8 ] = t13 * detInv; - te[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv; - te[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv; - te[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv; + this._x = euler._x; + this._y = euler._y; + this._z = euler._z; + this._order = euler._order; - te[ 12 ] = t14 * detInv; - te[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv; - te[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv; - te[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv; + this._onChangeCallback(); return this; } - scale( v ) { + setFromRotationMatrix( m, order = this._order, update = true ) { + + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + + 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': + + this._y = Math.asin( clamp( m13, - 1, 1 ) ); + + if ( Math.abs( m13 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m33 ); + this._z = Math.atan2( - m12, m11 ); + + } else { + + this._x = Math.atan2( m32, m22 ); + this._z = 0; + + } + + break; + + case 'YXZ': + + this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + + if ( Math.abs( m23 ) < 0.9999999 ) { + + this._y = Math.atan2( m13, m33 ); + this._z = Math.atan2( m21, m22 ); + + } else { + + this._y = Math.atan2( - m31, m11 ); + this._z = 0; + + } + + break; + + case 'ZXY': + + this._x = Math.asin( clamp( m32, - 1, 1 ) ); + + if ( Math.abs( m32 ) < 0.9999999 ) { + + this._y = Math.atan2( - m31, m33 ); + this._z = Math.atan2( - m12, m22 ); + + } else { + + this._y = 0; + this._z = Math.atan2( m21, m11 ); + + } + + break; + + case 'ZYX': + + this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + + if ( Math.abs( m31 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m33 ); + this._z = Math.atan2( m21, m11 ); + + } else { + + this._x = 0; + this._z = Math.atan2( - m12, m22 ); + + } + + break; + + case 'YZX': + + this._z = Math.asin( clamp( m21, - 1, 1 ) ); + + if ( Math.abs( m21 ) < 0.9999999 ) { + + this._x = Math.atan2( - m23, m22 ); + this._y = Math.atan2( - m31, m11 ); + + } else { + + this._x = 0; + this._y = Math.atan2( m13, m33 ); + + } + + break; + + case 'XZY': + + this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + + if ( Math.abs( m12 ) < 0.9999999 ) { + + this._x = Math.atan2( m32, m22 ); + this._y = Math.atan2( m13, m11 ); + + } else { + + this._x = Math.atan2( - m23, m33 ); + this._y = 0; + + } + + break; + + default: + + console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + + } + + this._order = order; + + if ( update === true ) this._onChangeCallback(); + + return this; + + } + + setFromQuaternion( q, order, update ) { + + _matrix$1.makeRotationFromQuaternion( q ); + + return this.setFromRotationMatrix( _matrix$1, order, update ); + + } + + setFromVector3( v, order = this._order ) { + + return this.set( v.x, v.y, v.z, order ); + + } + + reorder( newOrder ) { + + // WARNING: this discards revolution information -bhouston + + _quaternion$3.setFromEuler( this ); + + return this.setFromQuaternion( _quaternion$3, newOrder ); + + } + + equals( euler ) { + + return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + + } + + 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; + + } + + toArray( array = [], offset = 0 ) { + + array[ offset ] = this._x; + array[ offset + 1 ] = this._y; + array[ offset + 2 ] = this._z; + array[ offset + 3 ] = this._order; + + 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 ) { + + this.mask = ( 1 << channel | 0 ) >>> 0; + + } + + enable( channel ) { + + this.mask |= 1 << channel | 0; + + } + + enableAll() { + + this.mask = 0xffffffff | 0; + + } + + toggle( channel ) { + + this.mask ^= 1 << channel | 0; + + } + + disable( channel ) { + + this.mask &= ~ ( 1 << channel | 0 ); + + } + + disableAll() { + + this.mask = 0; + + } + + test( layers ) { + + return ( this.mask & layers.mask ) !== 0; + + } + + isEnabled( channel ) { + + return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + + } + + } + + let _object3DId = 0; + + const _v1$4 = /*@__PURE__*/ new Vector3(); + const _q1 = /*@__PURE__*/ new Quaternion(); + const _m1$1 = /*@__PURE__*/ new Matrix4(); + const _target = /*@__PURE__*/ new Vector3(); + + const _position$3 = /*@__PURE__*/ new Vector3(); + const _scale$2 = /*@__PURE__*/ new Vector3(); + const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + + const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); + const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + + const _addedEvent = { type: 'added' }; + const _removedEvent = { type: 'removed' }; + + class Object3D extends EventDispatcher { + + constructor() { + + super(); + + this.isObject3D = true; + + Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + + this.uuid = generateUUID(); + + this.name = ''; + this.type = 'Object3D'; + + this.parent = null; + this.children = []; + + this.up = Object3D.DEFAULT_UP.clone(); + + const position = new Vector3(); + const rotation = new Euler(); + const quaternion = new Quaternion(); + const scale = new Vector3( 1, 1, 1 ); + + function onRotationChange() { + + quaternion.setFromEuler( rotation, false ); + + } + + function onQuaternionChange() { + + rotation.setFromQuaternion( quaternion, undefined, false ); + + } + + 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() + } + } ); - const te = this.elements; - const x = v.x, y = v.y, z = v.z; + this.matrix = new Matrix4(); + this.matrixWorld = new Matrix4(); - te[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z; - te[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z; - te[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z; - te[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z; + this.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE; - return this; + this.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer + this.matrixWorldNeedsUpdate = false; - } + this.layers = new Layers(); + this.visible = true; - getMaxScaleOnAxis() { + this.castShadow = false; + this.receiveShadow = false; - const te = this.elements; + this.frustumCulled = true; + this.renderOrder = 0; - const scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ]; - const scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ]; - const scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ]; + this.animations = []; - return Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) ); + this.userData = {}; } - makeTranslation( x, y, z ) { + onBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - this.set( + onAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {} - 1, 0, 0, x, - 0, 1, 0, y, - 0, 0, 1, z, - 0, 0, 0, 1 + onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} - ); + onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} - return this; + applyMatrix4( matrix ) { - } + if ( this.matrixAutoUpdate ) this.updateMatrix(); - makeRotationX( theta ) { + this.matrix.premultiply( matrix ); - const c = Math.cos( theta ), s = Math.sin( theta ); + this.matrix.decompose( this.position, this.quaternion, this.scale ); - this.set( + } - 1, 0, 0, 0, - 0, c, - s, 0, - 0, s, c, 0, - 0, 0, 0, 1 + applyQuaternion( q ) { - ); + this.quaternion.premultiply( q ); return this; } - makeRotationY( theta ) { + setRotationFromAxisAngle( axis, angle ) { - const c = Math.cos( theta ), s = Math.sin( theta ); + // assumes axis is normalized - this.set( + this.quaternion.setFromAxisAngle( axis, angle ); - c, 0, s, 0, - 0, 1, 0, 0, - - s, 0, c, 0, - 0, 0, 0, 1 + } - ); + setRotationFromEuler( euler ) { - return this; + this.quaternion.setFromEuler( euler, true ); } - makeRotationZ( theta ) { - - const c = Math.cos( theta ), s = Math.sin( theta ); + setRotationFromMatrix( m ) { - this.set( + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - c, - s, 0, 0, - s, c, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 + this.quaternion.setFromRotationMatrix( m ); - ); + } - return this; + setRotationFromQuaternion( q ) { - } + // assumes q is normalized - makeRotationAxis( axis, angle ) { + this.quaternion.copy( q ); - // Based on http://www.gamedev.net/reference/articles/article1199.asp + } - const c = Math.cos( angle ); - const s = Math.sin( angle ); - const t = 1 - c; - const x = axis.x, y = axis.y, z = axis.z; - const tx = t * x, ty = t * y; + rotateOnAxis( axis, angle ) { - this.set( + // rotate object on axis in object space + // axis is assumed to be normalized - 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 + _q1.setFromAxisAngle( axis, angle ); - ); + this.quaternion.multiply( _q1 ); return this; } - makeScale( x, y, z ) { + rotateOnWorldAxis( axis, angle ) { - this.set( + // rotate object on axis in world space + // axis is assumed to be normalized + // method assumes no rotated parent - x, 0, 0, 0, - 0, y, 0, 0, - 0, 0, z, 0, - 0, 0, 0, 1 + _q1.setFromAxisAngle( axis, angle ); - ); + this.quaternion.premultiply( _q1 ); return this; } - makeShear( xy, xz, yx, yz, zx, zy ) { + rotateX( angle ) { - this.set( + return this.rotateOnAxis( _xAxis, angle ); - 1, yx, zx, 0, - xy, 1, zy, 0, - xz, yz, 1, 0, - 0, 0, 0, 1 + } - ); + rotateY( angle ) { - return this; + return this.rotateOnAxis( _yAxis, angle ); } - compose( position, quaternion, scale ) { - - const te = this.elements; + rotateZ( angle ) { - const x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w; - const x2 = x + x, y2 = y + y, z2 = z + z; - const xx = x * x2, xy = x * y2, xz = x * z2; - const yy = y * y2, yz = y * z2, zz = z * z2; - const wx = w * x2, wy = w * y2, wz = w * z2; + return this.rotateOnAxis( _zAxis, angle ); - const sx = scale.x, sy = scale.y, sz = scale.z; + } - te[ 0 ] = ( 1 - ( yy + zz ) ) * sx; - te[ 1 ] = ( xy + wz ) * sx; - te[ 2 ] = ( xz - wy ) * sx; - te[ 3 ] = 0; + translateOnAxis( axis, distance ) { - te[ 4 ] = ( xy - wz ) * sy; - te[ 5 ] = ( 1 - ( xx + zz ) ) * sy; - te[ 6 ] = ( yz + wx ) * sy; - te[ 7 ] = 0; + // translate object by distance along axis in object space + // axis is assumed to be normalized - te[ 8 ] = ( xz + wy ) * sz; - te[ 9 ] = ( yz - wx ) * sz; - te[ 10 ] = ( 1 - ( xx + yy ) ) * sz; - te[ 11 ] = 0; + _v1$4.copy( axis ).applyQuaternion( this.quaternion ); - te[ 12 ] = position.x; - te[ 13 ] = position.y; - te[ 14 ] = position.z; - te[ 15 ] = 1; + this.position.add( _v1$4.multiplyScalar( distance ) ); return this; } - decompose( position, quaternion, scale ) { - - const te = this.elements; + translateX( distance ) { - let sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length(); - const sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length(); - const sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length(); + return this.translateOnAxis( _xAxis, distance ); - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if ( det < 0 ) sx = - sx; + } - position.x = te[ 12 ]; - position.y = te[ 13 ]; - position.z = te[ 14 ]; + translateY( distance ) { - // scale the rotation part - _m1$2.copy( this ); + return this.translateOnAxis( _yAxis, distance ); - const invSX = 1 / sx; - const invSY = 1 / sy; - const invSZ = 1 / sz; + } - _m1$2.elements[ 0 ] *= invSX; - _m1$2.elements[ 1 ] *= invSX; - _m1$2.elements[ 2 ] *= invSX; + translateZ( distance ) { - _m1$2.elements[ 4 ] *= invSY; - _m1$2.elements[ 5 ] *= invSY; - _m1$2.elements[ 6 ] *= invSY; + return this.translateOnAxis( _zAxis, distance ); - _m1$2.elements[ 8 ] *= invSZ; - _m1$2.elements[ 9 ] *= invSZ; - _m1$2.elements[ 10 ] *= invSZ; + } - quaternion.setFromRotationMatrix( _m1$2 ); + localToWorld( vector ) { - scale.x = sx; - scale.y = sy; - scale.z = sz; + this.updateWorldMatrix( true, false ); - return this; + return vector.applyMatrix4( this.matrixWorld ); } - makePerspective( left, right, top, bottom, near, far ) { + worldToLocal( vector ) { - const te = this.elements; - const x = 2 * near / ( right - left ); - const y = 2 * near / ( top - bottom ); + this.updateWorldMatrix( true, false ); - const a = ( right + left ) / ( right - left ); - const b = ( top + bottom ) / ( top - bottom ); - const c = - ( far + near ) / ( far - near ); - const d = - 2 * far * near / ( far - near ); + return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); - te[ 0 ] = x; te[ 4 ] = 0; te[ 8 ] = a; te[ 12 ] = 0; - te[ 1 ] = 0; te[ 5 ] = y; te[ 9 ] = b; te[ 13 ] = 0; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = c; te[ 14 ] = d; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = - 1; te[ 15 ] = 0; + } - return this; + lookAt( x, y, z ) { - } + // This method does not support objects having non-uniformly-scaled parent(s) - makeOrthographic( left, right, top, bottom, near, far ) { + if ( x.isVector3 ) { - const te = this.elements; - const w = 1.0 / ( right - left ); - const h = 1.0 / ( top - bottom ); - const p = 1.0 / ( far - near ); + _target.copy( x ); - const x = ( right + left ) * w; - const y = ( top + bottom ) * h; - const z = ( far + near ) * p; + } else { - te[ 0 ] = 2 * w; te[ 4 ] = 0; te[ 8 ] = 0; te[ 12 ] = - x; - te[ 1 ] = 0; te[ 5 ] = 2 * h; te[ 9 ] = 0; te[ 13 ] = - y; - te[ 2 ] = 0; te[ 6 ] = 0; te[ 10 ] = - 2 * p; te[ 14 ] = - z; - te[ 3 ] = 0; te[ 7 ] = 0; te[ 11 ] = 0; te[ 15 ] = 1; + _target.set( x, y, z ); - return this; + } - } + const parent = this.parent; - equals( matrix ) { + this.updateWorldMatrix( true, false ); - const te = this.elements; - const me = matrix.elements; + _position$3.setFromMatrixPosition( this.matrixWorld ); - for ( let i = 0; i < 16; i ++ ) { + if ( this.isCamera || this.isLight ) { - if ( te[ i ] !== me[ i ] ) return false; + _m1$1.lookAt( _position$3, _target, this.up ); - } + } else { - return true; + _m1$1.lookAt( _target, _position$3, this.up ); - } + } - fromArray( array, offset = 0 ) { + this.quaternion.setFromRotationMatrix( _m1$1 ); - for ( let i = 0; i < 16; i ++ ) { + if ( parent ) { - this.elements[ i ] = array[ i + offset ]; + _m1$1.extractRotation( parent.matrixWorld ); + _q1.setFromRotationMatrix( _m1$1 ); + this.quaternion.premultiply( _q1.invert() ); } - return this; - } - toArray( array = [], offset = 0 ) { - - const te = this.elements; + add( object ) { - array[ offset ] = te[ 0 ]; - array[ offset + 1 ] = te[ 1 ]; - array[ offset + 2 ] = te[ 2 ]; - array[ offset + 3 ] = te[ 3 ]; + if ( arguments.length > 1 ) { - array[ offset + 4 ] = te[ 4 ]; - array[ offset + 5 ] = te[ 5 ]; - array[ offset + 6 ] = te[ 6 ]; - array[ offset + 7 ] = te[ 7 ]; + for ( let i = 0; i < arguments.length; i ++ ) { - array[ offset + 8 ] = te[ 8 ]; - array[ offset + 9 ] = te[ 9 ]; - array[ offset + 10 ] = te[ 10 ]; - array[ offset + 11 ] = te[ 11 ]; + this.add( arguments[ i ] ); - array[ offset + 12 ] = te[ 12 ]; - array[ offset + 13 ] = te[ 13 ]; - array[ offset + 14 ] = te[ 14 ]; - array[ offset + 15 ] = te[ 15 ]; + } - return array; + return this; - } + } - } + if ( object === this ) { - const _v1$5 = /*@__PURE__*/ new Vector3(); - const _m1$2 = /*@__PURE__*/ new Matrix4(); - const _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 ); - const _one = /*@__PURE__*/ new Vector3( 1, 1, 1 ); - const _x = /*@__PURE__*/ new Vector3(); - const _y = /*@__PURE__*/ new Vector3(); - const _z = /*@__PURE__*/ new Vector3(); + console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); + return this; - const _matrix$1 = /*@__PURE__*/ new Matrix4(); - const _quaternion$3 = /*@__PURE__*/ new Quaternion(); + } - class Euler { + if ( object && object.isObject3D ) { - constructor( x = 0, y = 0, z = 0, order = Euler.DefaultOrder ) { + if ( object.parent !== null ) { - this.isEuler = true; + object.parent.remove( object ); - this._x = x; - this._y = y; - this._z = z; - this._order = order; + } - } + object.parent = this; + this.children.push( object ); - get x() { + object.dispatchEvent( _addedEvent ); - return this._x; + } else { - } + console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); - set x( value ) { + } - this._x = value; - this._onChangeCallback(); + return this; } - get y() { - - return this._y; + remove( object ) { - } + if ( arguments.length > 1 ) { - set y( value ) { + for ( let i = 0; i < arguments.length; i ++ ) { - this._y = value; - this._onChangeCallback(); + this.remove( arguments[ i ] ); - } + } - get z() { + return this; - return this._z; + } - } + const index = this.children.indexOf( object ); - set z( value ) { + if ( index !== - 1 ) { - this._z = value; - this._onChangeCallback(); + object.parent = null; + this.children.splice( index, 1 ); - } + object.dispatchEvent( _removedEvent ); - get order() { + } - return this._order; + return this; } - set order( value ) { - - this._order = value; - this._onChangeCallback(); + removeFromParent() { - } + const parent = this.parent; - set( x, y, z, order = this._order ) { + if ( parent !== null ) { - this._x = x; - this._y = y; - this._z = z; - this._order = order; + parent.remove( this ); - this._onChangeCallback(); + } return this; } - clone() { + clear() { - return new this.constructor( this._x, this._y, this._z, this._order ); + return this.remove( ... this.children ); } - copy( euler ) { + attach( object ) { - this._x = euler._x; - this._y = euler._y; - this._z = euler._z; - this._order = euler._order; + // adds object as a child of this, while maintaining the object's world transform - this._onChangeCallback(); + // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) - return this; + this.updateWorldMatrix( true, false ); - } + _m1$1.copy( this.matrixWorld ).invert(); - setFromRotationMatrix( m, order = this._order, update = true ) { + if ( object.parent !== null ) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + object.parent.updateWorldMatrix( true, false ); - 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 ]; + _m1$1.multiply( object.parent.matrixWorld ); - switch ( order ) { + } - case 'XYZ': + object.applyMatrix4( _m1$1 ); - this._y = Math.asin( clamp( m13, - 1, 1 ) ); + this.add( object ); - if ( Math.abs( m13 ) < 0.9999999 ) { + object.updateWorldMatrix( false, true ); - this._x = Math.atan2( - m23, m33 ); - this._z = Math.atan2( - m12, m11 ); + return this; - } else { + } - this._x = Math.atan2( m32, m22 ); - this._z = 0; + getObjectById( id ) { - } + return this.getObjectByProperty( 'id', id ); - break; + } - case 'YXZ': + getObjectByName( name ) { - this._x = Math.asin( - clamp( m23, - 1, 1 ) ); + return this.getObjectByProperty( 'name', name ); - if ( Math.abs( m23 ) < 0.9999999 ) { + } - this._y = Math.atan2( m13, m33 ); - this._z = Math.atan2( m21, m22 ); + getObjectByProperty( name, value ) { - } else { + if ( this[ name ] === value ) return this; - this._y = Math.atan2( - m31, m11 ); - this._z = 0; + for ( let i = 0, l = this.children.length; i < l; i ++ ) { - } + const child = this.children[ i ]; + const object = child.getObjectByProperty( name, value ); - break; + if ( object !== undefined ) { - case 'ZXY': + return object; - this._x = Math.asin( clamp( m32, - 1, 1 ) ); + } - if ( Math.abs( m32 ) < 0.9999999 ) { + } - this._y = Math.atan2( - m31, m33 ); - this._z = Math.atan2( - m12, m22 ); + return undefined; - } else { + } - this._y = 0; - this._z = Math.atan2( m21, m11 ); + getObjectsByProperty( name, value, result = [] ) { - } + if ( this[ name ] === value ) result.push( this ); - break; + const children = this.children; - case 'ZYX': + for ( let i = 0, l = children.length; i < l; i ++ ) { - this._y = Math.asin( - clamp( m31, - 1, 1 ) ); + children[ i ].getObjectsByProperty( name, value, result ); - if ( Math.abs( m31 ) < 0.9999999 ) { + } - this._x = Math.atan2( m32, m33 ); - this._z = Math.atan2( m21, m11 ); + return result; - } else { + } - this._x = 0; - this._z = Math.atan2( - m12, m22 ); + getWorldPosition( target ) { - } + this.updateWorldMatrix( true, false ); - break; + return target.setFromMatrixPosition( this.matrixWorld ); - case 'YZX': + } - this._z = Math.asin( clamp( m21, - 1, 1 ) ); + getWorldQuaternion( target ) { - if ( Math.abs( m21 ) < 0.9999999 ) { + this.updateWorldMatrix( true, false ); - this._x = Math.atan2( - m23, m22 ); - this._y = Math.atan2( - m31, m11 ); + this.matrixWorld.decompose( _position$3, target, _scale$2 ); - } else { + return target; - this._x = 0; - this._y = Math.atan2( m13, m33 ); + } - } + getWorldScale( target ) { - break; + this.updateWorldMatrix( true, false ); - case 'XZY': + this.matrixWorld.decompose( _position$3, _quaternion$2, target ); - this._z = Math.asin( - clamp( m12, - 1, 1 ) ); + return target; - if ( Math.abs( m12 ) < 0.9999999 ) { + } - this._x = Math.atan2( m32, m22 ); - this._y = Math.atan2( m13, m11 ); + getWorldDirection( target ) { - } else { + this.updateWorldMatrix( true, false ); - this._x = Math.atan2( - m23, m33 ); - this._y = 0; + const e = this.matrixWorld.elements; + + return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + + } + + raycast( /* raycaster, intersects */ ) {} + + traverse( callback ) { - } + callback( this ); - break; + const children = this.children; - default: + for ( let i = 0, l = children.length; i < l; i ++ ) { - console.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order ); + children[ i ].traverse( callback ); } - this._order = order; + } - if ( update === true ) this._onChangeCallback(); + traverseVisible( callback ) { - return this; + if ( this.visible === false ) return; - } + callback( this ); - setFromQuaternion( q, order, update ) { + const children = this.children; - _matrix$1.makeRotationFromQuaternion( q ); + for ( let i = 0, l = children.length; i < l; i ++ ) { - return this.setFromRotationMatrix( _matrix$1, order, update ); + children[ i ].traverseVisible( callback ); - } + } - setFromVector3( v, order = this._order ) { + } - return this.set( v.x, v.y, v.z, order ); + traverseAncestors( callback ) { - } + const parent = this.parent; - reorder( newOrder ) { + if ( parent !== null ) { - // WARNING: this discards revolution information -bhouston + callback( parent ); - _quaternion$3.setFromEuler( this ); + parent.traverseAncestors( callback ); - return this.setFromQuaternion( _quaternion$3, newOrder ); + } } - equals( euler ) { + updateMatrix() { - return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); + this.matrix.compose( this.position, this.quaternion, this.scale ); - } + this.matrixWorldNeedsUpdate = true; - fromArray( array ) { + } - this._x = array[ 0 ]; - this._y = array[ 1 ]; - this._z = array[ 2 ]; - if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; + updateMatrixWorld( force ) { - this._onChangeCallback(); + if ( this.matrixAutoUpdate ) this.updateMatrix(); - return this; + if ( this.matrixWorldNeedsUpdate || force ) { - } + if ( this.parent === null ) { - toArray( array = [], offset = 0 ) { + this.matrixWorld.copy( this.matrix ); - array[ offset ] = this._x; - array[ offset + 1 ] = this._y; - array[ offset + 2 ] = this._z; - array[ offset + 3 ] = this._order; + } else { - return array; + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - } + } - _onChange( callback ) { + this.matrixWorldNeedsUpdate = false; - this._onChangeCallback = callback; + force = true; - return this; + } - } + // update children - _onChangeCallback() {} + const children = this.children; - *[ Symbol.iterator ]() { + for ( let i = 0, l = children.length; i < l; i ++ ) { - yield this._x; - yield this._y; - yield this._z; - yield this._order; + const child = children[ i ]; - } + if ( child.matrixWorldAutoUpdate === true || force === true ) { - // @deprecated since r138, 02cf0df1cb4575d5842fef9c85bb5a89fe020d53 + child.updateMatrixWorld( force ); - toVector3() { + } - console.error( 'THREE.Euler: .toVector3() has been removed. Use Vector3.setFromEuler() instead' ); + } } - } - - Euler.DefaultOrder = 'XYZ'; - Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; - - class Layers { + updateWorldMatrix( updateParents, updateChildren ) { - constructor() { + const parent = this.parent; - this.mask = 1 | 0; + if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { - } + parent.updateWorldMatrix( true, false ); - set( channel ) { + } - this.mask = ( 1 << channel | 0 ) >>> 0; + if ( this.matrixAutoUpdate ) this.updateMatrix(); - } + if ( this.parent === null ) { - enable( channel ) { + this.matrixWorld.copy( this.matrix ); - this.mask |= 1 << channel | 0; + } else { - } + this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); - enableAll() { + } - this.mask = 0xffffffff | 0; + // update children - } + if ( updateChildren === true ) { - toggle( channel ) { + const children = this.children; - this.mask ^= 1 << channel | 0; + for ( let i = 0, l = children.length; i < l; i ++ ) { - } + const child = children[ i ]; - disable( channel ) { + if ( child.matrixWorldAutoUpdate === true ) { - this.mask &= ~ ( 1 << channel | 0 ); + child.updateWorldMatrix( false, true ); - } + } - disableAll() { + } - this.mask = 0; + } } - test( layers ) { + toJSON( meta ) { - return ( this.mask & layers.mask ) !== 0; + // meta is a string when called from JSON.stringify + const isRootObject = ( meta === undefined || typeof meta === 'string' ); - } + const output = {}; - isEnabled( channel ) { + // meta is a hash used to collect geometries, materials. + // not providing it implies that this is the root object + // being serialized. + if ( isRootObject ) { - return ( this.mask & ( 1 << channel | 0 ) ) !== 0; + // initialize meta obj + meta = { + geometries: {}, + materials: {}, + textures: {}, + images: {}, + shapes: {}, + skeletons: {}, + animations: {}, + nodes: {} + }; - } + output.metadata = { + version: 4.6, + type: 'Object', + generator: 'Object3D.toJSON' + }; - } + } - let _object3DId = 0; + // standard Object3D serialization - const _v1$4 = /*@__PURE__*/ new Vector3(); - const _q1 = /*@__PURE__*/ new Quaternion(); - const _m1$1 = /*@__PURE__*/ new Matrix4(); - const _target = /*@__PURE__*/ new Vector3(); + const object = {}; - const _position$3 = /*@__PURE__*/ new Vector3(); - const _scale$2 = /*@__PURE__*/ new Vector3(); - const _quaternion$2 = /*@__PURE__*/ new Quaternion(); + object.uuid = this.uuid; + object.type = this.type; - const _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 ); - const _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - const _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 ); + if ( this.name !== '' ) object.name = this.name; + if ( this.castShadow === true ) object.castShadow = true; + if ( this.receiveShadow === true ) object.receiveShadow = true; + if ( this.visible === false ) object.visible = false; + if ( this.frustumCulled === false ) object.frustumCulled = false; + if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; + if ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData; - const _addedEvent = { type: 'added' }; - const _removedEvent = { type: 'removed' }; + object.layers = this.layers.mask; + object.matrix = this.matrix.toArray(); + object.up = this.up.toArray(); - class Object3D extends EventDispatcher { + if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; - constructor() { + // object specific properties - super(); + if ( this.isInstancedMesh ) { - this.isObject3D = true; + object.type = 'InstancedMesh'; + object.count = this.count; + object.instanceMatrix = this.instanceMatrix.toJSON(); + if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); - Object.defineProperty( this, 'id', { value: _object3DId ++ } ); + } - this.uuid = generateUUID(); + if ( this.isBatchedMesh ) { - this.name = ''; - this.type = 'Object3D'; + object.type = 'BatchedMesh'; + object.perObjectFrustumCulled = this.perObjectFrustumCulled; + object.sortObjects = this.sortObjects; - this.parent = null; - this.children = []; + object.drawRanges = this._drawRanges; + object.reservedRanges = this._reservedRanges; - this.up = Object3D.DefaultUp.clone(); + 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(), - const position = new Vector3(); - const rotation = new Euler(); - const quaternion = new Quaternion(); - const scale = new Vector3( 1, 1, 1 ); + sphereInitialized: bound.sphereInitialized, + sphereRadius: bound.sphere.radius, + sphereCenter: bound.sphere.center.toArray() + } ) ); - function onRotationChange() { + object.maxGeometryCount = this._maxGeometryCount; + object.maxVertexCount = this._maxVertexCount; + object.maxIndexCount = this._maxIndexCount; - quaternion.setFromEuler( rotation, false ); + object.geometryInitialized = this._geometryInitialized; + object.geometryCount = this._geometryCount; - } + object.matricesTexture = this._matricesTexture.toJSON( meta ); - function onQuaternionChange() { + if ( this.boundingSphere !== null ) { - rotation.setFromQuaternion( quaternion, undefined, false ); + object.boundingSphere = { + center: object.boundingSphere.center.toArray(), + radius: object.boundingSphere.radius + }; - } + } - rotation._onChange( onRotationChange ); - quaternion._onChange( onQuaternionChange ); + if ( this.boundingBox !== null ) { + + object.boundingBox = { + min: object.boundingBox.min.toArray(), + max: object.boundingBox.max.toArray() + }; - 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.matrix = new Matrix4(); - this.matrixWorld = new Matrix4(); + } - this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate; - this.matrixWorldNeedsUpdate = false; + // - this.matrixWorldAutoUpdate = Object3D.DefaultMatrixWorldAutoUpdate; // checked by the renderer + function serialize( library, element ) { - this.layers = new Layers(); - this.visible = true; + if ( library[ element.uuid ] === undefined ) { - this.castShadow = false; - this.receiveShadow = false; + library[ element.uuid ] = element.toJSON( meta ); - this.frustumCulled = true; - this.renderOrder = 0; + } - this.animations = []; + return element.uuid; - this.userData = {}; + } - } + if ( this.isScene ) { - onBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {} + if ( this.background ) { - onAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {} + if ( this.background.isColor ) { - applyMatrix4( matrix ) { + object.background = this.background.toJSON(); - if ( this.matrixAutoUpdate ) this.updateMatrix(); + } else if ( this.background.isTexture ) { - this.matrix.premultiply( matrix ); + object.background = this.background.toJSON( meta ).uuid; - this.matrix.decompose( this.position, this.quaternion, this.scale ); + } - } + } - applyQuaternion( q ) { + if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { - this.quaternion.premultiply( q ); + object.environment = this.environment.toJSON( meta ).uuid; - return this; + } - } + } else if ( this.isMesh || this.isLine || this.isPoints ) { - setRotationFromAxisAngle( axis, angle ) { + object.geometry = serialize( meta.geometries, this.geometry ); - // assumes axis is normalized + const parameters = this.geometry.parameters; - this.quaternion.setFromAxisAngle( axis, angle ); + if ( parameters !== undefined && parameters.shapes !== undefined ) { - } + const shapes = parameters.shapes; - setRotationFromEuler( euler ) { + if ( Array.isArray( shapes ) ) { - this.quaternion.setFromEuler( euler, true ); + for ( let i = 0, l = shapes.length; i < l; i ++ ) { - } + const shape = shapes[ i ]; - setRotationFromMatrix( m ) { + serialize( meta.shapes, shape ); - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + } - this.quaternion.setFromRotationMatrix( m ); + } else { - } + serialize( meta.shapes, shapes ); - setRotationFromQuaternion( q ) { + } - // assumes q is normalized + } - this.quaternion.copy( q ); + } - } + if ( this.isSkinnedMesh ) { - rotateOnAxis( axis, angle ) { + object.bindMode = this.bindMode; + object.bindMatrix = this.bindMatrix.toArray(); - // rotate object on axis in object space - // axis is assumed to be normalized + if ( this.skeleton !== undefined ) { - _q1.setFromAxisAngle( axis, angle ); + serialize( meta.skeletons, this.skeleton ); - this.quaternion.multiply( _q1 ); + object.skeleton = this.skeleton.uuid; - return this; + } - } + } - rotateOnWorldAxis( axis, angle ) { + if ( this.material !== undefined ) { - // rotate object on axis in world space - // axis is assumed to be normalized - // method assumes no rotated parent + if ( Array.isArray( this.material ) ) { - _q1.setFromAxisAngle( axis, angle ); + const uuids = []; - this.quaternion.premultiply( _q1 ); + for ( let i = 0, l = this.material.length; i < l; i ++ ) { - return this; + uuids.push( serialize( meta.materials, this.material[ i ] ) ); - } + } - rotateX( angle ) { + object.material = uuids; - return this.rotateOnAxis( _xAxis, angle ); + } else { - } + object.material = serialize( meta.materials, this.material ); - rotateY( angle ) { + } - return this.rotateOnAxis( _yAxis, angle ); + } - } + // - rotateZ( angle ) { + if ( this.children.length > 0 ) { - return this.rotateOnAxis( _zAxis, angle ); + object.children = []; - } + for ( let i = 0; i < this.children.length; i ++ ) { - translateOnAxis( axis, distance ) { + object.children.push( this.children[ i ].toJSON( meta ).object ); - // translate object by distance along axis in object space - // axis is assumed to be normalized + } - _v1$4.copy( axis ).applyQuaternion( this.quaternion ); + } - this.position.add( _v1$4.multiplyScalar( distance ) ); + // - return this; + if ( this.animations.length > 0 ) { - } + object.animations = []; - translateX( distance ) { + for ( let i = 0; i < this.animations.length; i ++ ) { - return this.translateOnAxis( _xAxis, distance ); + const animation = this.animations[ i ]; - } + object.animations.push( serialize( meta.animations, animation ) ); - translateY( distance ) { + } - return this.translateOnAxis( _yAxis, distance ); + } - } + if ( isRootObject ) { - translateZ( distance ) { + const geometries = extractFromCache( meta.geometries ); + const materials = extractFromCache( meta.materials ); + const textures = extractFromCache( meta.textures ); + const images = extractFromCache( meta.images ); + const shapes = extractFromCache( meta.shapes ); + const skeletons = extractFromCache( meta.skeletons ); + const animations = extractFromCache( meta.animations ); + const nodes = extractFromCache( meta.nodes ); - return this.translateOnAxis( _zAxis, distance ); + if ( geometries.length > 0 ) output.geometries = geometries; + if ( materials.length > 0 ) output.materials = materials; + if ( textures.length > 0 ) output.textures = textures; + if ( images.length > 0 ) output.images = images; + if ( shapes.length > 0 ) output.shapes = shapes; + if ( skeletons.length > 0 ) output.skeletons = skeletons; + if ( animations.length > 0 ) output.animations = animations; + if ( nodes.length > 0 ) output.nodes = nodes; - } + } - localToWorld( vector ) { + output.object = object; - return vector.applyMatrix4( this.matrixWorld ); + return output; - } + // extract data from the cache hash + // remove metadata on each item + // and return as array + function extractFromCache( cache ) { - worldToLocal( vector ) { + const values = []; + for ( const key in cache ) { - return vector.applyMatrix4( _m1$1.copy( this.matrixWorld ).invert() ); + const data = cache[ key ]; + delete data.metadata; + values.push( data ); - } + } - lookAt( x, y, z ) { + return values; - // This method does not support objects having non-uniformly-scaled parent(s) + } - if ( x.isVector3 ) { + } - _target.copy( x ); + clone( recursive ) { - } else { + return new this.constructor().copy( this, recursive ); - _target.set( x, y, z ); + } - } + copy( source, recursive = true ) { - const parent = this.parent; + this.name = source.name; - this.updateWorldMatrix( true, false ); + this.up.copy( source.up ); - _position$3.setFromMatrixPosition( this.matrixWorld ); + this.position.copy( source.position ); + this.rotation.order = source.rotation.order; + this.quaternion.copy( source.quaternion ); + this.scale.copy( source.scale ); - if ( this.isCamera || this.isLight ) { + this.matrix.copy( source.matrix ); + this.matrixWorld.copy( source.matrixWorld ); - _m1$1.lookAt( _position$3, _target, this.up ); + this.matrixAutoUpdate = source.matrixAutoUpdate; - } else { + this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; - _m1$1.lookAt( _target, _position$3, this.up ); + this.layers.mask = source.layers.mask; + this.visible = source.visible; - } + this.castShadow = source.castShadow; + this.receiveShadow = source.receiveShadow; - this.quaternion.setFromRotationMatrix( _m1$1 ); + this.frustumCulled = source.frustumCulled; + this.renderOrder = source.renderOrder; - if ( parent ) { + this.animations = source.animations.slice(); - _m1$1.extractRotation( parent.matrixWorld ); - _q1.setFromRotationMatrix( _m1$1 ); - this.quaternion.premultiply( _q1.invert() ); + this.userData = JSON.parse( JSON.stringify( source.userData ) ); - } + if ( recursive === true ) { - } + for ( let i = 0; i < source.children.length; i ++ ) { - add( object ) { + const child = source.children[ i ]; + this.add( child.clone() ); - if ( arguments.length > 1 ) { + } - for ( let i = 0; i < arguments.length; i ++ ) { + } - this.add( arguments[ i ] ); + return this; - } + } - return this; + } - } + Object3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 ); + Object3D.DEFAULT_MATRIX_AUTO_UPDATE = true; + Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true; - if ( object === this ) { + const _v0$1 = /*@__PURE__*/ new Vector3(); + const _v1$3 = /*@__PURE__*/ new Vector3(); + const _v2$2 = /*@__PURE__*/ new Vector3(); + const _v3$1 = /*@__PURE__*/ new Vector3(); - console.error( 'THREE.Object3D.add: object can\'t be added as a child of itself.', object ); - return this; + const _vab = /*@__PURE__*/ new Vector3(); + const _vac = /*@__PURE__*/ new Vector3(); + const _vbc = /*@__PURE__*/ new Vector3(); + const _vap = /*@__PURE__*/ new Vector3(); + const _vbp = /*@__PURE__*/ new Vector3(); + const _vcp = /*@__PURE__*/ new Vector3(); - } + let warnedGetUV = false; - if ( object && object.isObject3D ) { + class Triangle { - if ( object.parent !== null ) { + constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { - object.parent.remove( object ); + this.a = a; + this.b = b; + this.c = c; - } + } - object.parent = this; - this.children.push( object ); + static getNormal( a, b, c, target ) { - object.dispatchEvent( _addedEvent ); + target.subVectors( c, b ); + _v0$1.subVectors( a, b ); + target.cross( _v0$1 ); - } else { + const targetLengthSq = target.lengthSq(); + if ( targetLengthSq > 0 ) { - console.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object ); + return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); } - return this; + return target.set( 0, 0, 0 ); } - remove( object ) { + // static/instance method to calculate barycentric coordinates + // based on: http://www.blackpawn.com/texts/pointinpoly/default.html + static getBarycoord( point, a, b, c, target ) { - if ( arguments.length > 1 ) { + _v0$1.subVectors( c, a ); + _v1$3.subVectors( b, a ); + _v2$2.subVectors( point, a ); - for ( let i = 0; i < arguments.length; i ++ ) { + const dot00 = _v0$1.dot( _v0$1 ); + const dot01 = _v0$1.dot( _v1$3 ); + const dot02 = _v0$1.dot( _v2$2 ); + const dot11 = _v1$3.dot( _v1$3 ); + const dot12 = _v1$3.dot( _v2$2 ); - this.remove( arguments[ i ] ); + const denom = ( dot00 * dot11 - dot01 * dot01 ); - } + // collinear or singular triangle + if ( denom === 0 ) { - return this; + target.set( 0, 0, 0 ); + return null; } - const index = this.children.indexOf( object ); + const invDenom = 1 / denom; + const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; + const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; - if ( index !== - 1 ) { + // barycentric coordinates must always sum to 1 + return target.set( 1 - u - v, v, u ); - object.parent = null; - this.children.splice( index, 1 ); + } - object.dispatchEvent( _removedEvent ); + static containsPoint( point, a, b, c ) { + + // if the triangle is degenerate then we can't contain a point + if ( this.getBarycoord( point, a, b, c, _v3$1 ) === null ) { + + return false; } - return this; + return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); } - removeFromParent() { + static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { // @deprecated, r151 - const parent = this.parent; + if ( warnedGetUV === false ) { - if ( parent !== null ) { + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - parent.remove( this ); + warnedGetUV = true; } - return this; + return this.getInterpolation( point, p1, p2, p3, uv1, uv2, uv3, target ); } - clear() { - - for ( let i = 0; i < this.children.length; i ++ ) { - - const object = this.children[ i ]; + static getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) { - object.parent = null; + if ( this.getBarycoord( point, p1, p2, p3, _v3$1 ) === null ) { - object.dispatchEvent( _removedEvent ); + target.x = 0; + target.y = 0; + if ( 'z' in target ) target.z = 0; + if ( 'w' in target ) target.w = 0; + return null; } - this.children.length = 0; - - return this; + target.setScalar( 0 ); + target.addScaledVector( v1, _v3$1.x ); + target.addScaledVector( v2, _v3$1.y ); + target.addScaledVector( v3, _v3$1.z ); + return target; } - attach( object ) { - - // adds object as a child of this, while maintaining the object's world transform - - // Note: This method does not support scene graphs having non-uniformly-scaled nodes(s) + static isFrontFacing( a, b, c, direction ) { - this.updateWorldMatrix( true, false ); + _v0$1.subVectors( c, b ); + _v1$3.subVectors( a, b ); - _m1$1.copy( this.matrixWorld ).invert(); + // strictly front facing + return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; - if ( object.parent !== null ) { + } - object.parent.updateWorldMatrix( true, false ); + set( a, b, c ) { - _m1$1.multiply( object.parent.matrixWorld ); + this.a.copy( a ); + this.b.copy( b ); + this.c.copy( c ); - } + return this; - object.applyMatrix4( _m1$1 ); + } - this.add( object ); + setFromPointsAndIndices( points, i0, i1, i2 ) { - object.updateWorldMatrix( false, true ); + this.a.copy( points[ i0 ] ); + this.b.copy( points[ i1 ] ); + this.c.copy( points[ i2 ] ); return this; } - getObjectById( id ) { + setFromAttributeAndIndices( attribute, i0, i1, i2 ) { - return this.getObjectByProperty( 'id', id ); + this.a.fromBufferAttribute( attribute, i0 ); + this.b.fromBufferAttribute( attribute, i1 ); + this.c.fromBufferAttribute( attribute, i2 ); + + return this; } - getObjectByName( name ) { + clone() { - return this.getObjectByProperty( 'name', name ); + return new this.constructor().copy( this ); } - getObjectByProperty( name, value ) { - - if ( this[ name ] === value ) return this; - - for ( let i = 0, l = this.children.length; i < l; i ++ ) { + copy( triangle ) { - const child = this.children[ i ]; - const object = child.getObjectByProperty( name, value ); + this.a.copy( triangle.a ); + this.b.copy( triangle.b ); + this.c.copy( triangle.c ); - if ( object !== undefined ) { + return this; - return object; + } - } + getArea() { - } + _v0$1.subVectors( this.c, this.b ); + _v1$3.subVectors( this.a, this.b ); - return undefined; + return _v0$1.cross( _v1$3 ).length() * 0.5; } - getWorldPosition( target ) { - - this.updateWorldMatrix( true, false ); + getMidpoint( target ) { - return target.setFromMatrixPosition( this.matrixWorld ); + return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); } - getWorldQuaternion( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, target, _scale$2 ); + getNormal( target ) { - return target; + return Triangle.getNormal( this.a, this.b, this.c, target ); } - getWorldScale( target ) { - - this.updateWorldMatrix( true, false ); - - this.matrixWorld.decompose( _position$3, _quaternion$2, target ); + getPlane( target ) { - return target; + return target.setFromCoplanarPoints( this.a, this.b, this.c ); } - getWorldDirection( target ) { - - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; + getBarycoord( point, target ) { - return target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize(); + return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); } - raycast( /* raycaster, intersects */ ) {} - - traverse( callback ) { - - callback( this ); + getUV( point, uv1, uv2, uv3, target ) { // @deprecated, r151 - const children = this.children; + if ( warnedGetUV === false ) { - for ( let i = 0, l = children.length; i < l; i ++ ) { + console.warn( 'THREE.Triangle.getUV() has been renamed to THREE.Triangle.getInterpolation().' ); - children[ i ].traverse( callback ); + warnedGetUV = true; } - } - - traverseVisible( callback ) { - - if ( this.visible === false ) return; - - callback( this ); - - const children = this.children; + return Triangle.getInterpolation( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); - for ( let i = 0, l = children.length; i < l; i ++ ) { + } - children[ i ].traverseVisible( callback ); + getInterpolation( point, v1, v2, v3, target ) { - } + return Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target ); } - traverseAncestors( callback ) { - - const parent = this.parent; + containsPoint( point ) { - if ( parent !== null ) { + return Triangle.containsPoint( point, this.a, this.b, this.c ); - callback( parent ); + } - parent.traverseAncestors( callback ); + isFrontFacing( direction ) { - } + return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); } - updateMatrix() { - - this.matrix.compose( this.position, this.quaternion, this.scale ); + intersectsBox( box ) { - this.matrixWorldNeedsUpdate = true; + return box.intersectsTriangle( this ); } - updateMatrixWorld( force ) { - - if ( this.matrixAutoUpdate ) this.updateMatrix(); - - if ( this.matrixWorldNeedsUpdate || force ) { + closestPointToPoint( p, target ) { - if ( this.parent === null ) { + const a = this.a, b = this.b, c = this.c; + let v, w; - this.matrixWorld.copy( this.matrix ); + // algorithm thanks to Real-Time Collision Detection by Christer Ericson, + // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., + // under the accompanying license; see chapter 5.1.5 for detailed explanation. + // basically, we're distinguishing which of the voronoi regions of the triangle + // the point lies in with the minimum amount of redundant computation. - } else { + _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 ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + // vertex region of A; barycentric coords (1, 0, 0) + return target.copy( a ); - } + } - this.matrixWorldNeedsUpdate = false; + _vbp.subVectors( p, b ); + const d3 = _vab.dot( _vbp ); + const d4 = _vac.dot( _vbp ); + if ( d3 >= 0 && d4 <= d3 ) { - force = true; + // vertex region of B; barycentric coords (0, 1, 0) + return target.copy( b ); } - // update children - - const children = this.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + const vc = d1 * d4 - d3 * d2; + if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { - const child = children[ i ]; + v = d1 / ( d1 - d3 ); + // edge region of AB; barycentric coords (1-v, v, 0) + return target.copy( a ).addScaledVector( _vab, v ); - if ( child.matrixWorldAutoUpdate === true || force === true ) { + } - child.updateMatrixWorld( force ); + _vcp.subVectors( p, c ); + const d5 = _vab.dot( _vcp ); + const d6 = _vac.dot( _vcp ); + if ( d6 >= 0 && d5 <= d6 ) { - } + // vertex region of C; barycentric coords (0, 0, 1) + return target.copy( c ); } - } + const vb = d5 * d2 - d1 * d6; + if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { - updateWorldMatrix( updateParents, updateChildren ) { + w = d2 / ( d2 - d6 ); + // edge region of AC; barycentric coords (1-w, 0, w) + return target.copy( a ).addScaledVector( _vac, w ); - const parent = this.parent; + } - if ( updateParents === true && parent !== null && parent.matrixWorldAutoUpdate === true ) { + const va = d3 * d6 - d5 * d4; + if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { - parent.updateWorldMatrix( true, false ); + _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 } - if ( this.matrixAutoUpdate ) this.updateMatrix(); + // face region + const denom = 1 / ( va + vb + vc ); + // u = va * denom + v = vb * denom; + w = vc * denom; - if ( this.parent === null ) { + return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); - this.matrixWorld.copy( this.matrix ); + } - } else { + equals( triangle ) { - this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); + return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); - } + } - // update children + } - if ( updateChildren === true ) { + const _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF, + 'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2, + 'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50, + 'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B, + 'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B, + 'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F, + 'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3, + 'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222, + 'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700, + 'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4, + 'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00, + 'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3, + 'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA, + 'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32, + 'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3, + 'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC, + 'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD, + 'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6, + 'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9, + 'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F, + 'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE, + 'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA, + 'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0, + 'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 }; - const children = this.children; + const _hslA = { h: 0, s: 0, l: 0 }; + const _hslB = { h: 0, s: 0, l: 0 }; - for ( let i = 0, l = children.length; i < l; i ++ ) { + function hue2rgb( p, q, t ) { - const child = children[ i ]; + 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; - if ( child.matrixWorldAutoUpdate === true ) { + } - child.updateWorldMatrix( false, true ); + class Color { - } + constructor( r, g, b ) { - } + this.isColor = true; - } + this.r = 1; + this.g = 1; + this.b = 1; - } + return this.set( r, g, b ); - toJSON( meta ) { + } - // meta is a string when called from JSON.stringify - const isRootObject = ( meta === undefined || typeof meta === 'string' ); + set( r, g, b ) { - const output = {}; + if ( g === undefined && b === undefined ) { - // meta is a hash used to collect geometries, materials. - // not providing it implies that this is the root object - // being serialized. - if ( isRootObject ) { + // r is THREE.Color, hex or string - // initialize meta obj - meta = { - geometries: {}, - materials: {}, - textures: {}, - images: {}, - shapes: {}, - skeletons: {}, - animations: {}, - nodes: {} - }; + const value = r; - output.metadata = { - version: 4.5, - type: 'Object', - generator: 'Object3D.toJSON' - }; + if ( value && value.isColor ) { - } + this.copy( value ); - // standard Object3D serialization + } else if ( typeof value === 'number' ) { - const object = {}; + this.setHex( value ); - object.uuid = this.uuid; - object.type = this.type; + } else if ( typeof value === 'string' ) { - if ( this.name !== '' ) object.name = this.name; - if ( this.castShadow === true ) object.castShadow = true; - if ( this.receiveShadow === true ) object.receiveShadow = true; - if ( this.visible === false ) object.visible = false; - if ( this.frustumCulled === false ) object.frustumCulled = false; - if ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder; - if ( JSON.stringify( this.userData ) !== '{}' ) object.userData = this.userData; + this.setStyle( value ); - object.layers = this.layers.mask; - object.matrix = this.matrix.toArray(); + } - if ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false; + } else { - // object specific properties + this.setRGB( r, g, b ); - if ( this.isInstancedMesh ) { + } - object.type = 'InstancedMesh'; - object.count = this.count; - object.instanceMatrix = this.instanceMatrix.toJSON(); - if ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON(); + return this; - } + } - // + setScalar( scalar ) { - function serialize( library, element ) { + this.r = scalar; + this.g = scalar; + this.b = scalar; - if ( library[ element.uuid ] === undefined ) { + return this; - library[ element.uuid ] = element.toJSON( meta ); + } - } + setHex( hex, colorSpace = SRGBColorSpace ) { - return element.uuid; + hex = Math.floor( hex ); - } + this.r = ( hex >> 16 & 255 ) / 255; + this.g = ( hex >> 8 & 255 ) / 255; + this.b = ( hex & 255 ) / 255; - if ( this.isScene ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - if ( this.background ) { + return this; - if ( this.background.isColor ) { + } - object.background = this.background.toJSON(); + setRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) { - } else if ( this.background.isTexture ) { + this.r = r; + this.g = g; + this.b = b; - object.background = this.background.toJSON( meta ).uuid; + ColorManagement.toWorkingColorSpace( this, colorSpace ); - } + return this; - } + } - if ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) { + setHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) { - object.environment = this.environment.toJSON( meta ).uuid; + // h,s,l ranges are in 0.0 - 1.0 + h = euclideanModulo( h, 1 ); + s = clamp( s, 0, 1 ); + l = clamp( l, 0, 1 ); - } + if ( s === 0 ) { - } else if ( this.isMesh || this.isLine || this.isPoints ) { + this.r = this.g = this.b = l; - object.geometry = serialize( meta.geometries, this.geometry ); + } else { - const parameters = this.geometry.parameters; + const p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); + const q = ( 2 * l ) - p; - if ( parameters !== undefined && parameters.shapes !== undefined ) { + this.r = hue2rgb( q, p, h + 1 / 3 ); + this.g = hue2rgb( q, p, h ); + this.b = hue2rgb( q, p, h - 1 / 3 ); - const shapes = parameters.shapes; + } - if ( Array.isArray( shapes ) ) { + ColorManagement.toWorkingColorSpace( this, colorSpace ); - for ( let i = 0, l = shapes.length; i < l; i ++ ) { + return this; - const shape = shapes[ i ]; + } - serialize( meta.shapes, shape ); + setStyle( style, colorSpace = SRGBColorSpace ) { - } + function handleAlpha( string ) { - } else { + if ( string === undefined ) return; - serialize( meta.shapes, shapes ); + if ( parseFloat( string ) < 1 ) { - } + console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' ); } } - if ( this.isSkinnedMesh ) { - object.bindMode = this.bindMode; - object.bindMatrix = this.bindMatrix.toArray(); + let m; - if ( this.skeleton !== undefined ) { + if ( m = /^(\w+)\(([^\)]*)\)/.exec( style ) ) { - serialize( meta.skeletons, this.skeleton ); + // rgb / hsl - object.skeleton = this.skeleton.uuid; + let color; + const name = m[ 1 ]; + const components = m[ 2 ]; - } + switch ( name ) { - } + case 'rgb': + case 'rgba': - if ( this.material !== undefined ) { + if ( color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - if ( Array.isArray( this.material ) ) { + // rgb(255,0,0) rgba(255,0,0,0.5) - const uuids = []; + handleAlpha( color[ 4 ] ); - for ( let i = 0, l = this.material.length; i < l; i ++ ) { + 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 + ); - uuids.push( serialize( meta.materials, this.material[ i ] ) ); + } - } + if ( color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec( components ) ) { - object.material = uuids; + // 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; - } else { + case 'hsl': + case 'hsla': - object.material = serialize( meta.materials, this.material ); + 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 + ); - if ( this.children.length > 0 ) { + } - object.children = []; + break; - for ( let i = 0; i < this.children.length; i ++ ) { + default: - object.children.push( this.children[ i ].toJSON( meta ).object ); + console.warn( 'THREE.Color: Unknown color model ' + style ); } - } + } else if ( m = /^\#([A-Fa-f\d]+)$/.exec( style ) ) { - // + // hex color - if ( this.animations.length > 0 ) { + const hex = m[ 1 ]; + const size = hex.length; - object.animations = []; + if ( size === 3 ) { - for ( let i = 0; i < this.animations.length; i ++ ) { + // #ff0 + return this.setRGB( + parseInt( hex.charAt( 0 ), 16 ) / 15, + parseInt( hex.charAt( 1 ), 16 ) / 15, + parseInt( hex.charAt( 2 ), 16 ) / 15, + colorSpace + ); - const animation = this.animations[ i ]; + } else if ( size === 6 ) { - object.animations.push( serialize( meta.animations, animation ) ); + // #ff0000 + return this.setHex( parseInt( hex, 16 ), colorSpace ); - } + } else { - } + console.warn( 'THREE.Color: Invalid hex color ' + style ); - if ( isRootObject ) { + } - const geometries = extractFromCache( meta.geometries ); - const materials = extractFromCache( meta.materials ); - const textures = extractFromCache( meta.textures ); - const images = extractFromCache( meta.images ); - const shapes = extractFromCache( meta.shapes ); - const skeletons = extractFromCache( meta.skeletons ); - const animations = extractFromCache( meta.animations ); - const nodes = extractFromCache( meta.nodes ); + } else if ( style && style.length > 0 ) { - if ( geometries.length > 0 ) output.geometries = geometries; - if ( materials.length > 0 ) output.materials = materials; - if ( textures.length > 0 ) output.textures = textures; - if ( images.length > 0 ) output.images = images; - if ( shapes.length > 0 ) output.shapes = shapes; - if ( skeletons.length > 0 ) output.skeletons = skeletons; - if ( animations.length > 0 ) output.animations = animations; - if ( nodes.length > 0 ) output.nodes = nodes; + return this.setColorName( style, colorSpace ); } - output.object = object; + return this; - return output; + } - // extract data from the cache hash - // remove metadata on each item - // and return as array - function extractFromCache( cache ) { + setColorName( style, colorSpace = SRGBColorSpace ) { - const values = []; - for ( const key in cache ) { + // color keywords + const hex = _colorKeywords[ style.toLowerCase() ]; - const data = cache[ key ]; - delete data.metadata; - values.push( data ); + if ( hex !== undefined ) { - } + // red + this.setHex( hex, colorSpace ); - return values; + } else { + + // unknown color + console.warn( 'THREE.Color: Unknown color ' + style ); } + return this; + } - clone( recursive ) { + clone() { - return new this.constructor().copy( this, recursive ); + return new this.constructor( this.r, this.g, this.b ); } - copy( source, recursive = true ) { - - this.name = source.name; - - this.up.copy( source.up ); + copy( color ) { - this.position.copy( source.position ); - this.rotation.order = source.rotation.order; - this.quaternion.copy( source.quaternion ); - this.scale.copy( source.scale ); + this.r = color.r; + this.g = color.g; + this.b = color.b; - this.matrix.copy( source.matrix ); - this.matrixWorld.copy( source.matrixWorld ); + return this; - this.matrixAutoUpdate = source.matrixAutoUpdate; - this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate; + } - this.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate; + copySRGBToLinear( color ) { - this.layers.mask = source.layers.mask; - this.visible = source.visible; + this.r = SRGBToLinear( color.r ); + this.g = SRGBToLinear( color.g ); + this.b = SRGBToLinear( color.b ); - this.castShadow = source.castShadow; - this.receiveShadow = source.receiveShadow; + return this; - this.frustumCulled = source.frustumCulled; - this.renderOrder = source.renderOrder; + } - this.userData = JSON.parse( JSON.stringify( source.userData ) ); + copyLinearToSRGB( color ) { - if ( recursive === true ) { + this.r = LinearToSRGB( color.r ); + this.g = LinearToSRGB( color.g ); + this.b = LinearToSRGB( color.b ); - for ( let i = 0; i < source.children.length; i ++ ) { + return this; - const child = source.children[ i ]; - this.add( child.clone() ); + } - } + convertSRGBToLinear() { - } + this.copySRGBToLinear( this ); return this; } - } + convertLinearToSRGB() { - Object3D.DefaultUp = /*@__PURE__*/ new Vector3( 0, 1, 0 ); - Object3D.DefaultMatrixAutoUpdate = true; - Object3D.DefaultMatrixWorldAutoUpdate = true; + this.copyLinearToSRGB( this ); - const _v0$1 = /*@__PURE__*/ new Vector3(); - const _v1$3 = /*@__PURE__*/ new Vector3(); - const _v2$2 = /*@__PURE__*/ new Vector3(); - const _v3$1 = /*@__PURE__*/ new Vector3(); + return this; - const _vab = /*@__PURE__*/ new Vector3(); - const _vac = /*@__PURE__*/ new Vector3(); - const _vbc = /*@__PURE__*/ new Vector3(); - const _vap = /*@__PURE__*/ new Vector3(); - const _vbp = /*@__PURE__*/ new Vector3(); - const _vcp = /*@__PURE__*/ new Vector3(); + } - class Triangle { + getHex( colorSpace = SRGBColorSpace ) { - constructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) { + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - this.a = a; - this.b = b; - this.c = c; + return Math.round( clamp( _color.r * 255, 0, 255 ) ) * 65536 + Math.round( clamp( _color.g * 255, 0, 255 ) ) * 256 + Math.round( clamp( _color.b * 255, 0, 255 ) ); } - static getNormal( a, b, c, target ) { + getHexString( colorSpace = SRGBColorSpace ) { - target.subVectors( c, b ); - _v0$1.subVectors( a, b ); - target.cross( _v0$1 ); + return ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 ); - const targetLengthSq = target.lengthSq(); - if ( targetLengthSq > 0 ) { + } - return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) ); + getHSL( target, colorSpace = ColorManagement.workingColorSpace ) { - } + // h,s,l ranges are in 0.0 - 1.0 - return target.set( 0, 0, 0 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - } + const r = _color.r, g = _color.g, b = _color.b; - // static/instance method to calculate barycentric coordinates - // based on: http://www.blackpawn.com/texts/pointinpoly/default.html - static getBarycoord( point, a, b, c, target ) { + const max = Math.max( r, g, b ); + const min = Math.min( r, g, b ); - _v0$1.subVectors( c, a ); - _v1$3.subVectors( b, a ); - _v2$2.subVectors( point, a ); + let hue, saturation; + const lightness = ( min + max ) / 2.0; - const dot00 = _v0$1.dot( _v0$1 ); - const dot01 = _v0$1.dot( _v1$3 ); - const dot02 = _v0$1.dot( _v2$2 ); - const dot11 = _v1$3.dot( _v1$3 ); - const dot12 = _v1$3.dot( _v2$2 ); + if ( min === max ) { - const denom = ( dot00 * dot11 - dot01 * dot01 ); + hue = 0; + saturation = 0; - // collinear or singular triangle - if ( denom === 0 ) { + } else { + + const delta = max - min; - // arbitrary location outside of triangle? - // not sure if this is the best idea, maybe should be returning undefined - return target.set( - 2, - 1, - 1 ); + saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); - } + switch ( max ) { - const invDenom = 1 / denom; - const u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; - const v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; + case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; + case g: hue = ( b - r ) / delta + 2; break; + case b: hue = ( r - g ) / delta + 4; break; - // barycentric coordinates must always sum to 1 - return target.set( 1 - u - v, v, u ); + } - } + hue /= 6; - static containsPoint( point, a, b, c ) { + } - this.getBarycoord( point, a, b, c, _v3$1 ); + target.h = hue; + target.s = saturation; + target.l = lightness; - return ( _v3$1.x >= 0 ) && ( _v3$1.y >= 0 ) && ( ( _v3$1.x + _v3$1.y ) <= 1 ); + return target; } - static getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) { + getRGB( target, colorSpace = ColorManagement.workingColorSpace ) { - this.getBarycoord( point, p1, p2, p3, _v3$1 ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - target.set( 0, 0 ); - target.addScaledVector( uv1, _v3$1.x ); - target.addScaledVector( uv2, _v3$1.y ); - target.addScaledVector( uv3, _v3$1.z ); + target.r = _color.r; + target.g = _color.g; + target.b = _color.b; return target; } - static isFrontFacing( a, b, c, direction ) { + getStyle( colorSpace = SRGBColorSpace ) { - _v0$1.subVectors( c, b ); - _v1$3.subVectors( a, b ); + ColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace ); - // strictly front facing - return ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false; + const r = _color.r, g = _color.g, b = _color.b; - } + if ( colorSpace !== SRGBColorSpace ) { - set( a, b, c ) { + // Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/). + return `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`; - this.a.copy( a ); - this.b.copy( b ); - this.c.copy( c ); + } - return this; + return `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`; } - setFromPointsAndIndices( points, i0, i1, i2 ) { + offsetHSL( h, s, l ) { - this.a.copy( points[ i0 ] ); - this.b.copy( points[ i1 ] ); - this.c.copy( points[ i2 ] ); + this.getHSL( _hslA ); - return this; + return this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l ); } - setFromAttributeAndIndices( attribute, i0, i1, i2 ) { + add( color ) { - this.a.fromBufferAttribute( attribute, i0 ); - this.b.fromBufferAttribute( attribute, i1 ); - this.c.fromBufferAttribute( attribute, i2 ); + this.r += color.r; + this.g += color.g; + this.b += color.b; return this; } - clone() { - - return new this.constructor().copy( this ); - - } - - copy( triangle ) { + addColors( color1, color2 ) { - this.a.copy( triangle.a ); - this.b.copy( triangle.b ); - this.c.copy( triangle.c ); + this.r = color1.r + color2.r; + this.g = color1.g + color2.g; + this.b = color1.b + color2.b; return this; } - getArea() { + addScalar( s ) { - _v0$1.subVectors( this.c, this.b ); - _v1$3.subVectors( this.a, this.b ); + this.r += s; + this.g += s; + this.b += s; - return _v0$1.cross( _v1$3 ).length() * 0.5; + return this; } - getMidpoint( target ) { + sub( color ) { - return target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); + this.r = Math.max( 0, this.r - color.r ); + this.g = Math.max( 0, this.g - color.g ); + this.b = Math.max( 0, this.b - color.b ); + + return this; } - getNormal( target ) { + multiply( color ) { - return Triangle.getNormal( this.a, this.b, this.c, target ); + this.r *= color.r; + this.g *= color.g; + this.b *= color.b; + + return this; } - getPlane( target ) { + multiplyScalar( s ) { - return target.setFromCoplanarPoints( this.a, this.b, this.c ); + this.r *= s; + this.g *= s; + this.b *= s; + + return this; } - getBarycoord( point, target ) { + lerp( color, alpha ) { - return Triangle.getBarycoord( point, this.a, this.b, this.c, target ); + this.r += ( color.r - this.r ) * alpha; + this.g += ( color.g - this.g ) * alpha; + this.b += ( color.b - this.b ) * alpha; + + return this; } - getUV( point, uv1, uv2, uv3, target ) { + lerpColors( color1, color2, alpha ) { + + this.r = color1.r + ( color2.r - color1.r ) * alpha; + this.g = color1.g + ( color2.g - color1.g ) * alpha; + this.b = color1.b + ( color2.b - color1.b ) * alpha; - return Triangle.getUV( point, this.a, this.b, this.c, uv1, uv2, uv3, target ); + return this; } - containsPoint( point ) { + lerpHSL( color, alpha ) { - return Triangle.containsPoint( point, this.a, this.b, this.c ); + 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 ); - isFrontFacing( direction ) { + this.setHSL( h, s, l ); - return Triangle.isFrontFacing( this.a, this.b, this.c, direction ); + return this; } - intersectsBox( box ) { + setFromVector3( v ) { - return box.intersectsTriangle( this ); + this.r = v.x; + this.g = v.y; + this.b = v.z; - } + return this; - closestPointToPoint( p, target ) { + } - const a = this.a, b = this.b, c = this.c; - let v, w; + applyMatrix3( m ) { - // algorithm thanks to Real-Time Collision Detection by Christer Ericson, - // published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc., - // under the accompanying license; see chapter 5.1.5 for detailed explanation. - // basically, we're distinguishing which of the voronoi regions of the triangle - // the point lies in with the minimum amount of redundant computation. + const r = this.r, g = this.g, b = this.b; + const e = m.elements; - _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 ) { + 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; - // vertex region of A; barycentric coords (1, 0, 0) - return target.copy( a ); + return this; - } + } - _vbp.subVectors( p, b ); - const d3 = _vab.dot( _vbp ); - const d4 = _vac.dot( _vbp ); - if ( d3 >= 0 && d4 <= d3 ) { + equals( c ) { - // vertex region of B; barycentric coords (0, 1, 0) - return target.copy( b ); + return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); - } + } - const vc = d1 * d4 - d3 * d2; - if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) { + fromArray( array, offset = 0 ) { - v = d1 / ( d1 - d3 ); - // edge region of AB; barycentric coords (1-v, v, 0) - return target.copy( a ).addScaledVector( _vab, v ); + this.r = array[ offset ]; + this.g = array[ offset + 1 ]; + this.b = array[ offset + 2 ]; - } + return this; - _vcp.subVectors( p, c ); - const d5 = _vab.dot( _vcp ); - const d6 = _vac.dot( _vcp ); - if ( d6 >= 0 && d5 <= d6 ) { + } - // vertex region of C; barycentric coords (0, 0, 1) - return target.copy( c ); + toArray( array = [], offset = 0 ) { - } + array[ offset ] = this.r; + array[ offset + 1 ] = this.g; + array[ offset + 2 ] = this.b; - const vb = d5 * d2 - d1 * d6; - if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) { + return array; - w = d2 / ( d2 - d6 ); - // edge region of AC; barycentric coords (1-w, 0, w) - return target.copy( a ).addScaledVector( _vac, w ); + } - } + fromBufferAttribute( attribute, index ) { - const va = d3 * d6 - d5 * d4; - if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) { + this.r = attribute.getX( index ); + this.g = attribute.getY( index ); + this.b = attribute.getZ( index ); - _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 + return this; - } + } - // face region - const denom = 1 / ( va + vb + vc ); - // u = va * denom - v = vb * denom; - w = vc * denom; + toJSON() { - return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w ); + return this.getHex(); } - equals( triangle ) { + *[ Symbol.iterator ]() { - return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); + yield this.r; + yield this.g; + yield this.b; } } - let materialId = 0; + const _color = /*@__PURE__*/ new Color(); + + Color.NAMES = _colorKeywords; + + let _materialId = 0; class Material extends EventDispatcher { @@ -8320,7 +8940,7 @@ this.isMaterial = true; - Object.defineProperty( this, 'id', { value: materialId ++ } ); + Object.defineProperty( this, 'id', { value: _materialId ++ } ); this.uuid = generateUUID(); @@ -8333,6 +8953,7 @@ this.opacity = 1; this.transparent = false; + this.alphaHash = false; this.blendSrc = SrcAlphaFactor; this.blendDst = OneMinusSrcAlphaFactor; @@ -8340,6 +8961,8 @@ 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; @@ -8372,6 +8995,7 @@ this.alphaToCoverage = false; this.premultipliedAlpha = false; + this.forceSinglePass = false; this.visible = true; @@ -8425,7 +9049,7 @@ if ( newValue === undefined ) { - console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); + console.warn( `THREE.Material: parameter '${ key }' has value of undefined.` ); continue; } @@ -8434,7 +9058,7 @@ if ( currentValue === undefined ) { - console.warn( 'THREE.' + this.type + ': \'' + key + '\' is not a property of this material.' ); + console.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` ); continue; } @@ -8472,7 +9096,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'Material', generator: 'Material.toJSON' } @@ -8537,6 +9161,15 @@ } + if ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy; + if ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation; + + if ( this.anisotropyMap && this.anisotropyMap.isTexture ) { + + data.anisotropyMap = this.anisotropyMap.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; @@ -8617,24 +9250,33 @@ if ( this.blending !== NormalBlending ) data.blending = this.blending; if ( this.side !== FrontSide ) data.side = this.side; - if ( this.vertexColors ) data.vertexColors = true; + if ( this.vertexColors === true ) data.vertexColors = true; if ( this.opacity < 1 ) data.opacity = this.opacity; - if ( this.transparent === true ) data.transparent = this.transparent; - - data.depthFunc = this.depthFunc; - data.depthTest = this.depthTest; - data.depthWrite = this.depthWrite; - data.colorWrite = this.colorWrite; - - data.stencilWrite = this.stencilWrite; - data.stencilWriteMask = this.stencilWriteMask; - data.stencilFunc = this.stencilFunc; - data.stencilRef = this.stencilRef; - data.stencilFuncMask = this.stencilFuncMask; - data.stencilFail = this.stencilFail; - data.stencilZFail = this.stencilZFail; - data.stencilZPass = this.stencilZPass; + if ( this.transparent === true ) data.transparent = true; + + if ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc; + if ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst; + if ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation; + if ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha; + if ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha; + if ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha; + if ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex(); + if ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha; + + if ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc; + if ( this.depthTest === false ) data.depthTest = this.depthTest; + if ( this.depthWrite === false ) data.depthWrite = this.depthWrite; + if ( this.colorWrite === false ) data.colorWrite = this.colorWrite; + + if ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask; + if ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc; + if ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef; + if ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask; + if ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail; + if ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail; + if ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass; + if ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite; // rotation (SpriteMaterial) if ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation; @@ -8651,15 +9293,17 @@ if ( this.dithering === true ) data.dithering = true; if ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest; - if ( this.alphaToCoverage === true ) data.alphaToCoverage = this.alphaToCoverage; - if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = this.premultipliedAlpha; + if ( this.alphaHash === true ) data.alphaHash = true; + if ( this.alphaToCoverage === true ) data.alphaToCoverage = true; + if ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true; + if ( this.forceSinglePass === true ) data.forceSinglePass = true; - if ( this.wireframe === true ) data.wireframe = this.wireframe; + if ( this.wireframe === true ) data.wireframe = true; if ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth; if ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap; if ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin; - if ( this.flatShading === true ) data.flatShading = this.flatShading; + if ( this.flatShading === true ) data.flatShading = true; if ( this.visible === false ) data.visible = false; @@ -8667,7 +9311,7 @@ if ( this.fog === false ) data.fog = false; - if ( JSON.stringify( this.userData ) !== '{}' ) data.userData = this.userData; + if ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData; // TODO: Copied from Object3D.toJSON @@ -8724,6 +9368,8 @@ 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; @@ -8771,8 +9417,10 @@ 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; @@ -8879,7 +9527,7 @@ class BufferAttribute { - constructor( array, itemSize, normalized ) { + constructor( array, itemSize, normalized = false ) { if ( Array.isArray( array ) ) { @@ -8894,10 +9542,12 @@ this.array = array; this.itemSize = itemSize; this.count = array !== undefined ? array.length / itemSize : 0; - this.normalized = normalized === true; + this.normalized = normalized; this.usage = StaticDrawUsage; - this.updateRange = { offset: 0, count: - 1 }; + this._updateRange = { offset: 0, count: - 1 }; + this.updateRanges = []; + this.gpuType = FloatType; this.version = 0; @@ -8911,6 +9561,13 @@ } + get updateRange() { + + console.warn( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159 + return this._updateRange; + + } + setUsage( value ) { this.usage = value; @@ -8919,6 +9576,18 @@ } + addUpdateRange( start, count ) { + + this.updateRanges.push( { start, count } ); + + } + + clearUpdateRanges() { + + this.updateRanges.length = 0; + + } + copy( source ) { this.name = source.name; @@ -8928,6 +9597,7 @@ this.normalized = source.normalized; this.usage = source.usage; + this.gpuType = source.gpuType; return this; @@ -9043,6 +9713,26 @@ } + getComponent( index, component ) { + + let value = this.array[ index * this.itemSize + component ]; + + if ( this.normalized ) value = denormalize( value, this.array ); + + return value; + + } + + setComponent( index, component, value ) { + + if ( this.normalized ) value = normalize( value, this.array ); + + this.array[ index * this.itemSize + component ] = value; + + return this; + + } + getX( index ) { let x = this.array[ index * this.itemSize ]; @@ -9208,38 +9898,11 @@ if ( this.name !== '' ) data.name = this.name; if ( this.usage !== StaticDrawUsage ) data.usage = this.usage; - if ( this.updateRange.offset !== 0 || this.updateRange.count !== - 1 ) data.updateRange = this.updateRange; return data; } - // @deprecated - - copyColorsArray() { - - console.error( 'THREE.BufferAttribute: copyColorsArray() was removed in r144.' ); - - } - - copyVector2sArray() { - - console.error( 'THREE.BufferAttribute: copyVector2sArray() was removed in r144.' ); - - } - - copyVector3sArray() { - - console.error( 'THREE.BufferAttribute: copyVector3sArray() was removed in r144.' ); - - } - - copyVector4sArray() { - - console.error( 'THREE.BufferAttribute: copyVector4sArray() was removed in r144.' ); - - } - } class Uint16BufferAttribute extends BufferAttribute { @@ -9273,12 +9936,12 @@ } - let _id$1 = 0; + let _id$2 = 0; const _m1 = /*@__PURE__*/ new Matrix4(); const _obj = /*@__PURE__*/ new Object3D(); const _offset = /*@__PURE__*/ new Vector3(); - const _box$1 = /*@__PURE__*/ new Box3(); + const _box$2 = /*@__PURE__*/ new Box3(); const _boxMorphTargets = /*@__PURE__*/ new Box3(); const _vector$8 = /*@__PURE__*/ new Vector3(); @@ -9290,7 +9953,7 @@ this.isBufferGeometry = true; - Object.defineProperty( this, 'id', { value: _id$1 ++ } ); + Object.defineProperty( this, 'id', { value: _id$2 ++ } ); this.uuid = generateUUID(); @@ -9585,20 +10248,20 @@ for ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) { const morphAttribute = morphAttributesPosition[ i ]; - _box$1.setFromBufferAttribute( morphAttribute ); + _box$2.setFromBufferAttribute( morphAttribute ); if ( this.morphTargetsRelative ) { - _vector$8.addVectors( this.boundingBox.min, _box$1.min ); + _vector$8.addVectors( this.boundingBox.min, _box$2.min ); this.boundingBox.expandByPoint( _vector$8 ); - _vector$8.addVectors( this.boundingBox.max, _box$1.max ); + _vector$8.addVectors( this.boundingBox.max, _box$2.max ); this.boundingBox.expandByPoint( _vector$8 ); } else { - this.boundingBox.expandByPoint( _box$1.min ); - this.boundingBox.expandByPoint( _box$1.max ); + this.boundingBox.expandByPoint( _box$2.min ); + this.boundingBox.expandByPoint( _box$2.max ); } @@ -9647,7 +10310,7 @@ const center = this.boundingSphere.center; - _box$1.setFromBufferAttribute( position ); + _box$2.setFromBufferAttribute( position ); // process morph attributes if present @@ -9660,16 +10323,16 @@ if ( this.morphTargetsRelative ) { - _vector$8.addVectors( _box$1.min, _boxMorphTargets.min ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.min, _boxMorphTargets.min ); + _box$2.expandByPoint( _vector$8 ); - _vector$8.addVectors( _box$1.max, _boxMorphTargets.max ); - _box$1.expandByPoint( _vector$8 ); + _vector$8.addVectors( _box$2.max, _boxMorphTargets.max ); + _box$2.expandByPoint( _vector$8 ); } else { - _box$1.expandByPoint( _boxMorphTargets.min ); - _box$1.expandByPoint( _boxMorphTargets.max ); + _box$2.expandByPoint( _boxMorphTargets.min ); + _box$2.expandByPoint( _boxMorphTargets.max ); } @@ -9677,7 +10340,7 @@ } - _box$1.getCenter( center ); + _box$2.getCenter( center ); // second, try to find a boundingSphere with a radius smaller than the // boundingSphere of the boundingBox: sqrt(3) smaller in the best case @@ -9989,15 +10652,6 @@ } - // @deprecated since r144 - - merge() { - - console.error( 'THREE.BufferGeometry.merge() has been removed. Use THREE.BufferGeometryUtils.mergeBufferGeometries() instead.' ); - return this; - - } - normalizeNormals() { const normals = this.attributes.normal; @@ -10120,7 +10774,7 @@ const data = { metadata: { - version: 4.5, + version: 4.6, type: 'BufferGeometry', generator: 'BufferGeometry.toJSON' } @@ -10231,7 +10885,7 @@ clone() { - return new this.constructor().copy( this ); + return new this.constructor().copy( this ); } @@ -10336,10 +10990,6 @@ this.userData = source.userData; - // geometry generator parameters - - if ( source.parameters !== undefined ) this.parameters = Object.assign( {}, source.parameters ); - return this; } @@ -10352,26 +11002,26 @@ } - const _inverseMatrix$2 = /*@__PURE__*/ new Matrix4(); - const _ray$2 = /*@__PURE__*/ new Ray(); - const _sphere$3 = /*@__PURE__*/ new Sphere(); + const _inverseMatrix$3 = /*@__PURE__*/ new Matrix4(); + const _ray$3 = /*@__PURE__*/ new Ray(); + const _sphere$6 = /*@__PURE__*/ new Sphere(); + const _sphereHitAt = /*@__PURE__*/ new Vector3(); const _vA$1 = /*@__PURE__*/ new Vector3(); const _vB$1 = /*@__PURE__*/ new Vector3(); const _vC$1 = /*@__PURE__*/ new Vector3(); const _tempA = /*@__PURE__*/ new Vector3(); - const _tempB = /*@__PURE__*/ new Vector3(); - const _tempC = /*@__PURE__*/ new Vector3(); - const _morphA = /*@__PURE__*/ new Vector3(); - const _morphB = /*@__PURE__*/ new Vector3(); - const _morphC = /*@__PURE__*/ new Vector3(); const _uvA$1 = /*@__PURE__*/ new Vector2(); const _uvB$1 = /*@__PURE__*/ new Vector2(); const _uvC$1 = /*@__PURE__*/ new Vector2(); + const _normalA = /*@__PURE__*/ new Vector3(); + const _normalB = /*@__PURE__*/ new Vector3(); + const _normalC = /*@__PURE__*/ new Vector3(); + const _intersectionPoint = /*@__PURE__*/ new Vector3(); const _intersectionPointWorld = /*@__PURE__*/ new Vector3(); @@ -10408,7 +11058,7 @@ } - this.material = source.material; + this.material = Array.isArray( source.material ) ? source.material.slice() : source.material; this.geometry = source.geometry; return this; @@ -10426,24 +11076,68 @@ const morphAttribute = morphAttributes[ keys[ 0 ] ]; - if ( morphAttribute !== undefined ) { + if ( morphAttribute !== undefined ) { + + this.morphTargetInfluences = []; + this.morphTargetDictionary = {}; + + for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + + const name = morphAttribute[ m ].name || String( m ); + + this.morphTargetInfluences.push( 0 ); + this.morphTargetDictionary[ name ] = m; + + } + + } + + } + + } + + getVertexPosition( index, target ) { + + const geometry = this.geometry; + const position = geometry.attributes.position; + const morphPosition = geometry.morphAttributes.position; + const morphTargetsRelative = geometry.morphTargetsRelative; + + target.fromBufferAttribute( position, index ); + + const morphInfluences = this.morphTargetInfluences; + + if ( morphPosition && morphInfluences ) { + + _morphA.set( 0, 0, 0 ); + + for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { + + const influence = morphInfluences[ i ]; + const morphAttribute = morphPosition[ i ]; + + if ( influence === 0 ) continue; + + _tempA.fromBufferAttribute( morphAttribute, index ); - this.morphTargetInfluences = []; - this.morphTargetDictionary = {}; + if ( morphTargetsRelative ) { - for ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) { + _morphA.addScaledVector( _tempA, influence ); - const name = morphAttribute[ m ].name || String( m ); + } else { - this.morphTargetInfluences.push( 0 ); - this.morphTargetDictionary[ name ] = m; + _morphA.addScaledVector( _tempA.sub( target ), influence ); } } + target.add( _morphA ); + } + return target; + } raycast( raycaster, intersects ) { @@ -10454,36 +11148,56 @@ if ( material === undefined ) return; - // Checking boundingSphere distance to ray + // test with bounding sphere in world space if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); - _sphere$3.copy( geometry.boundingSphere ); - _sphere$3.applyMatrix4( matrixWorld ); + _sphere$6.copy( geometry.boundingSphere ); + _sphere$6.applyMatrix4( matrixWorld ); - if ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return; + // check distance from ray origin to bounding sphere - // + _ray$3.copy( raycaster.ray ).recast( raycaster.near ); + + if ( _sphere$6.containsPoint( _ray$3.origin ) === false ) { + + if ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return; + + if ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return; + + } + + // convert ray to local space of mesh - _inverseMatrix$2.copy( matrixWorld ).invert(); - _ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 ); + _inverseMatrix$3.copy( matrixWorld ).invert(); + _ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 ); - // Check boundingBox before continuing + // test with bounding box in local space if ( geometry.boundingBox !== null ) { - if ( _ray$2.intersectsBox( geometry.boundingBox ) === false ) return; + if ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return; } + // test for intersections with geometry + + this._computeIntersections( raycaster, intersects, _ray$3 ); + + } + + _computeIntersections( raycaster, intersects, rayLocalSpace ) { + let intersection; + const geometry = this.geometry; + const material = this.material; + const index = geometry.index; const position = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; const uv = geometry.attributes.uv; - const uv2 = geometry.attributes.uv2; + const uv1 = geometry.attributes.uv1; + const normal = geometry.attributes.normal; const groups = geometry.groups; const drawRange = geometry.drawRange; @@ -10507,7 +11221,7 @@ const b = index.getX( j + 1 ); const c = index.getX( j + 2 ); - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10532,7 +11246,7 @@ const b = index.getX( i + 1 ); const c = index.getX( i + 2 ); - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10565,7 +11279,7 @@ const b = j + 1; const c = j + 2; - intersection = checkBufferGeometryIntersection( this, groupMaterial, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10590,7 +11304,7 @@ const b = i + 1; const c = i + 2; - intersection = checkBufferGeometryIntersection( this, material, raycaster, _ray$2, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ); + intersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c ); if ( intersection ) { @@ -10619,7 +11333,7 @@ } else { - intersect = ray.intersectTriangle( pA, pB, pC, material.side !== DoubleSide, point ); + intersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point ); } @@ -10640,82 +11354,50 @@ } - function checkBufferGeometryIntersection( object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c ) { - - _vA$1.fromBufferAttribute( position, a ); - _vB$1.fromBufferAttribute( position, b ); - _vC$1.fromBufferAttribute( position, c ); - - const morphInfluences = object.morphTargetInfluences; - - if ( morphPosition && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); + function checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) { - for ( let i = 0, il = morphPosition.length; i < il; i ++ ) { + object.getVertexPosition( a, _vA$1 ); + object.getVertexPosition( b, _vB$1 ); + object.getVertexPosition( c, _vC$1 ); - const influence = morphInfluences[ i ]; - const morphAttribute = morphPosition[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morphAttribute, a ); - _tempB.fromBufferAttribute( morphAttribute, b ); - _tempC.fromBufferAttribute( morphAttribute, c ); - - if ( morphTargetsRelative ) { + const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); + if ( intersection ) { - } else { + if ( uv ) { - _morphA.addScaledVector( _tempA.sub( _vA$1 ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB$1 ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC$1 ), influence ); + _uvA$1.fromBufferAttribute( uv, a ); + _uvB$1.fromBufferAttribute( uv, b ); + _uvC$1.fromBufferAttribute( uv, c ); - } + intersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); } - _vA$1.add( _morphA ); - _vB$1.add( _morphB ); - _vC$1.add( _morphC ); - - } - - if ( object.isSkinnedMesh ) { - - object.boneTransform( a, _vA$1 ); - object.boneTransform( b, _vB$1 ); - object.boneTransform( c, _vC$1 ); - - } + if ( uv1 ) { - const intersection = checkIntersection( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint ); + _uvA$1.fromBufferAttribute( uv1, a ); + _uvB$1.fromBufferAttribute( uv1, b ); + _uvC$1.fromBufferAttribute( uv1, c ); - if ( intersection ) { + intersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + intersection.uv2 = intersection.uv1; // @deprecated, r152 - if ( uv ) { + } - _uvA$1.fromBufferAttribute( uv, a ); - _uvB$1.fromBufferAttribute( uv, b ); - _uvC$1.fromBufferAttribute( uv, c ); + if ( normal ) { - intersection.uv = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + _normalA.fromBufferAttribute( normal, a ); + _normalB.fromBufferAttribute( normal, b ); + _normalC.fromBufferAttribute( normal, c ); - } + intersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() ); - if ( uv2 ) { + if ( intersection.normal.dot( ray.direction ) > 0 ) { - _uvA$1.fromBufferAttribute( uv2, a ); - _uvB$1.fromBufferAttribute( uv2, b ); - _uvC$1.fromBufferAttribute( uv2, c ); + intersection.normal.multiplyScalar( - 1 ); - intersection.uv2 = Triangle.getUV( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() ); + } } @@ -10894,6 +11576,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); @@ -10923,7 +11615,16 @@ property.isVector2 || property.isVector3 || property.isVector4 || property.isTexture || property.isQuaternion ) ) { - dst[ u ][ p ] = property.clone(); + if ( property.isRenderTargetTexture ) { + + console.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' ); + dst[ u ][ p ] = null; + + } else { + + dst[ u ][ p ] = property.clone(); + + } } else if ( Array.isArray( property ) ) { @@ -10982,11 +11683,11 @@ if ( renderer.getRenderTarget() === null ) { // https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398 - return renderer.outputEncoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; + return renderer.outputColorSpace; } - return LinearSRGBColorSpace; + return ColorManagement.workingColorSpace; } @@ -11024,11 +11725,14 @@ this.lights = false; // set to use scene lights this.clipping = false; // set to use user-defined clipping planes + this.forceSinglePass = true; + this.extensions = { derivatives: false, // set to use derivatives fragDepth: false, // set to use fragment depth values drawBuffers: false, // set to use draw buffers - shaderTextureLOD: false // set to use shader texture LOD + shaderTextureLOD: false, // set to use shader texture LOD + clipCullDistance: false // set to use vertex shader clipping }; // When rendered geometry doesn't include these attributes but the material does, @@ -11036,7 +11740,7 @@ this.defaultAttributeValues = { 'color': [ 1, 1, 1 ], 'uv': [ 0, 0 ], - 'uv2': [ 0, 0 ] + 'uv1': [ 0, 0 ] }; this.index0AttributeName = undefined; @@ -11157,6 +11861,9 @@ data.vertexShader = this.vertexShader; data.fragmentShader = this.fragmentShader; + data.lights = this.lights; + data.clipping = this.clipping; + const extensions = {}; for ( const key in this.extensions ) { @@ -11188,6 +11895,8 @@ this.projectionMatrix = new Matrix4(); this.projectionMatrixInverse = new Matrix4(); + this.coordinateSystem = WebGLCoordinateSystem; + } copy( source, recursive ) { @@ -11199,17 +11908,15 @@ this.projectionMatrix.copy( source.projectionMatrix ); this.projectionMatrixInverse.copy( source.projectionMatrixInverse ); + this.coordinateSystem = source.coordinateSystem; + return this; } getWorldDirection( target ) { - this.updateWorldMatrix( true, false ); - - const e = this.matrixWorld.elements; - - return target.set( - e[ 8 ], - e[ 9 ], - e[ 10 ] ).normalize(); + return super.getWorldDirection( target ).negate(); } @@ -11436,7 +12143,7 @@ const skew = this.filmOffset; if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); - this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far ); + this.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -11478,88 +12185,154 @@ this.type = 'CubeCamera'; this.renderTarget = renderTarget; + this.coordinateSystem = null; + this.activeMipmapLevel = 0; const cameraPX = new PerspectiveCamera( fov, aspect, near, far ); cameraPX.layers = this.layers; - cameraPX.up.set( 0, 1, 0 ); - cameraPX.lookAt( 1, 0, 0 ); this.add( cameraPX ); const cameraNX = new PerspectiveCamera( fov, aspect, near, far ); cameraNX.layers = this.layers; - cameraNX.up.set( 0, 1, 0 ); - cameraNX.lookAt( - 1, 0, 0 ); this.add( cameraNX ); const cameraPY = new PerspectiveCamera( fov, aspect, near, far ); cameraPY.layers = this.layers; - cameraPY.up.set( 0, 0, - 1 ); - cameraPY.lookAt( 0, 1, 0 ); this.add( cameraPY ); const cameraNY = new PerspectiveCamera( fov, aspect, near, far ); cameraNY.layers = this.layers; - cameraNY.up.set( 0, 0, 1 ); - cameraNY.lookAt( 0, - 1, 0 ); this.add( cameraNY ); const cameraPZ = new PerspectiveCamera( fov, aspect, near, far ); cameraPZ.layers = this.layers; - cameraPZ.up.set( 0, 1, 0 ); - cameraPZ.lookAt( 0, 0, 1 ); this.add( cameraPZ ); const cameraNZ = new PerspectiveCamera( fov, aspect, near, far ); cameraNZ.layers = this.layers; - cameraNZ.up.set( 0, 1, 0 ); - cameraNZ.lookAt( 0, 0, - 1 ); this.add( cameraNZ ); } + updateCoordinateSystem() { + + const coordinateSystem = this.coordinateSystem; + + const cameras = this.children.concat(); + + const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras; + + for ( const camera of cameras ) this.remove( camera ); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + 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 if ( coordinateSystem === WebGPUCoordinateSystem ) { + + 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 { + + throw new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem ); + + } + + for ( const camera of cameras ) { + + this.add( camera ); + + camera.updateMatrixWorld(); + + } + + } + update( renderer, scene ) { if ( this.parent === null ) this.updateMatrixWorld(); - const renderTarget = this.renderTarget; + const { renderTarget, activeMipmapLevel } = this; + + if ( this.coordinateSystem !== renderer.coordinateSystem ) { + + this.coordinateSystem = renderer.coordinateSystem; + + this.updateCoordinateSystem(); + + } const [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children; const currentRenderTarget = renderer.getRenderTarget(); + const currentActiveCubeFace = renderer.getActiveCubeFace(); + const currentActiveMipmapLevel = renderer.getActiveMipmapLevel(); - const currentToneMapping = renderer.toneMapping; const currentXrEnabled = renderer.xr.enabled; - renderer.toneMapping = NoToneMapping; renderer.xr.enabled = false; const generateMipmaps = renderTarget.texture.generateMipmaps; renderTarget.texture.generateMipmaps = false; - renderer.setRenderTarget( renderTarget, 0 ); + renderer.setRenderTarget( renderTarget, 0, activeMipmapLevel ); renderer.render( scene, cameraPX ); - renderer.setRenderTarget( renderTarget, 1 ); + renderer.setRenderTarget( renderTarget, 1, activeMipmapLevel ); renderer.render( scene, cameraNX ); - renderer.setRenderTarget( renderTarget, 2 ); + renderer.setRenderTarget( renderTarget, 2, activeMipmapLevel ); renderer.render( scene, cameraPY ); - renderer.setRenderTarget( renderTarget, 3 ); + renderer.setRenderTarget( renderTarget, 3, activeMipmapLevel ); renderer.render( scene, cameraNY ); - renderer.setRenderTarget( renderTarget, 4 ); + renderer.setRenderTarget( renderTarget, 4, activeMipmapLevel ); renderer.render( scene, cameraPZ ); + // mipmaps are generated during the last call of render() + // at this point, all sides of the cube render target are defined + renderTarget.texture.generateMipmaps = generateMipmaps; - renderer.setRenderTarget( renderTarget, 5 ); + renderer.setRenderTarget( renderTarget, 5, activeMipmapLevel ); renderer.render( scene, cameraNZ ); - renderer.setRenderTarget( currentRenderTarget ); + renderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel ); - renderer.toneMapping = currentToneMapping; renderer.xr.enabled = currentXrEnabled; renderTarget.texture.needsPMREMUpdate = true; @@ -11570,12 +12343,12 @@ class CubeTexture extends Texture { - constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ) { + constructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) { images = images !== undefined ? images : []; mapping = mapping !== undefined ? mapping : CubeReflectionMapping; - super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding ); + super( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ); this.isCubeTexture = true; @@ -11608,7 +12381,15 @@ const image = { width: size, height: size, depth: 1 }; const images = [ image, image, image, image, image, image ]; - this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding ); + if ( options.encoding !== undefined ) { + + // @deprecated, r152 + warnOnce( 'THREE.WebGLCubeRenderTarget: option.encoding has been replaced by option.colorSpace.' ); + options.colorSpace = options.encoding === sRGBEncoding ? SRGBColorSpace : NoColorSpace; + + } + + this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace ); // By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js) // in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words, @@ -11628,7 +12409,7 @@ fromEquirectangularTexture( renderer, texture ) { this.texture.type = texture.type; - this.texture.encoding = texture.encoding; + this.texture.colorSpace = texture.colorSpace; this.texture.generateMipmaps = texture.generateMipmaps; this.texture.minFilter = texture.minFilter; @@ -11833,7 +12614,7 @@ projectPoint( point, target ) { - return target.copy( this.normal ).multiplyScalar( - this.distanceToPoint( point ) ).add( point ); + return target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) ); } @@ -11865,7 +12646,7 @@ } - return target.copy( direction ).multiplyScalar( t ).add( line.start ); + return target.copy( line.start ).addScaledVector( direction, t ); } @@ -11934,7 +12715,7 @@ } - const _sphere$2 = /*@__PURE__*/ new Sphere(); + const _sphere$5 = /*@__PURE__*/ new Sphere(); const _vector$7 = /*@__PURE__*/ new Vector3(); class Frustum { @@ -11974,7 +12755,7 @@ } - setFromProjectionMatrix( m ) { + setFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) { const planes = this.planes; const me = m.elements; @@ -11988,7 +12769,20 @@ planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); - planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + if ( coordinateSystem === WebGLCoordinateSystem ) { + + planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); + + } else if ( coordinateSystem === WebGPUCoordinateSystem ) { + + planes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize(); + + } else { + + throw new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem ); + + } return this; @@ -11996,23 +12790,33 @@ intersectsObject( object ) { - const geometry = object.geometry; + if ( object.boundingSphere !== undefined ) { - if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + + _sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld ); - _sphere$2.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); + } else { + + const geometry = object.geometry; + + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + + _sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld ); - return this.intersectsSphere( _sphere$2 ); + } + + return this.intersectsSphere( _sphere$5 ); } intersectsSprite( sprite ) { - _sphere$2.center.set( 0, 0, 0 ); - _sphere$2.radius = 0.7071067811865476; - _sphere$2.applyMatrix4( sprite.matrixWorld ); + _sphere$5.center.set( 0, 0, 0 ); + _sphere$5.radius = 0.7071067811865476; + _sphere$5.applyMatrix4( sprite.matrixWorld ); - return this.intersectsSphere( _sphere$2 ); + return this.intersectsSphere( _sphere$5 ); } @@ -12152,6 +12956,7 @@ const array = attribute.array; const usage = attribute.usage; + const size = array.byteLength; const buffer = gl.createBuffer(); @@ -12164,7 +12969,7 @@ if ( array instanceof Float32Array ) { - type = 5126; + type = gl.FLOAT; } else if ( array instanceof Uint16Array ) { @@ -12172,7 +12977,7 @@ if ( isWebGL2 ) { - type = 5131; + type = gl.HALF_FLOAT; } else { @@ -12182,33 +12987,33 @@ } else { - type = 5123; + type = gl.UNSIGNED_SHORT; } } else if ( array instanceof Int16Array ) { - type = 5122; + type = gl.SHORT; } else if ( array instanceof Uint32Array ) { - type = 5125; + type = gl.UNSIGNED_INT; } else if ( array instanceof Int32Array ) { - type = 5124; + type = gl.INT; } else if ( array instanceof Int8Array ) { - type = 5120; + type = gl.BYTE; } else if ( array instanceof Uint8Array ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else if ( array instanceof Uint8ClampedArray ) { - type = 5121; + type = gl.UNSIGNED_BYTE; } else { @@ -12220,7 +13025,8 @@ buffer: buffer, type: type, bytesPerElement: array.BYTES_PER_ELEMENT, - version: attribute.version + version: attribute.version, + size: size }; } @@ -12228,17 +13034,43 @@ function updateBuffer( buffer, attribute, bufferType ) { const array = attribute.array; - const updateRange = attribute.updateRange; + const updateRange = attribute._updateRange; // deprecated + const updateRanges = attribute.updateRanges; gl.bindBuffer( bufferType, buffer ); - if ( updateRange.count === - 1 ) { + if ( updateRange.count === - 1 && updateRanges.length === 0 ) { // Not using update ranges - gl.bufferSubData( bufferType, 0, array ); - } else { + } + + if ( updateRanges.length !== 0 ) { + + for ( let i = 0, l = updateRanges.length; i < l; i ++ ) { + + const range = updateRanges[ i ]; + if ( isWebGL2 ) { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array, range.start, range.count ); + + } else { + + gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT, + array.subarray( range.start, range.start + range.count ) ); + + } + + } + + attribute.clearUpdateRanges(); + + } + + // deprecated + if ( updateRange.count !== - 1 ) { if ( isWebGL2 ) { @@ -12317,6 +13149,12 @@ } else if ( data.version < attribute.version ) { + if ( data.size !== attribute.array.byteLength ) { + + throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' ); + + } + updateBuffer( data.buffer, attribute, bufferType ); data.version = attribute.version; @@ -12411,6 +13249,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); @@ -12419,7 +13267,11 @@ } - var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif"; + var alphahash_fragment = "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\n#endif"; + + var alphahash_pars_fragment = "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D( vec2 value ) {\n\t\treturn fract( 1.0e4 * sin( 17.0 * value.x + 0.1 * value.y ) * ( 0.1 + abs( sin( 13.0 * value.y + value.x ) ) ) );\n\t}\n\tfloat hash3D( vec3 value ) {\n\t\treturn hash2D( vec2( hash2D( value.xy ), value.z ) );\n\t}\n\tfloat getAlphaHashThreshold( vec3 position ) {\n\t\tfloat maxDeriv = max(\n\t\t\tlength( dFdx( position.xyz ) ),\n\t\t\tlength( dFdy( position.xyz ) )\n\t\t);\n\t\tfloat pixScale = 1.0 / ( ALPHA_HASH_SCALE * maxDeriv );\n\t\tvec2 pixScales = vec2(\n\t\t\texp2( floor( log2( pixScale ) ) ),\n\t\t\texp2( ceil( log2( pixScale ) ) )\n\t\t);\n\t\tvec2 alpha = vec2(\n\t\t\thash3D( floor( pixScales.x * position.xyz ) ),\n\t\t\thash3D( floor( pixScales.y * position.xyz ) )\n\t\t);\n\t\tfloat lerpFactor = fract( log2( pixScale ) );\n\t\tfloat x = ( 1.0 - lerpFactor ) * alpha.x + lerpFactor * alpha.y;\n\t\tfloat a = min( lerpFactor, 1.0 - lerpFactor );\n\t\tvec3 cases = vec3(\n\t\t\tx * x / ( 2.0 * a * ( 1.0 - a ) ),\n\t\t\t( x - 0.5 * a ) / ( 1.0 - a ),\n\t\t\t1.0 - ( ( 1.0 - x ) * ( 1.0 - x ) / ( 2.0 * a * ( 1.0 - a ) ) )\n\t\t);\n\t\tfloat threshold = ( x < ( 1.0 - a ) )\n\t\t\t? ( ( x < a ) ? cases.x : cases.y )\n\t\t\t: cases.z;\n\t\treturn clamp( threshold , 1.0e-6, 1.0 );\n\t}\n#endif"; + + var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\n#endif"; var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; @@ -12427,19 +13279,23 @@ var alphatest_pars_fragment = "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"; - var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; + var aomap_fragment = "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_CLEARCOAT ) \n\t\tclearcoatSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_SHEEN ) \n\t\tsheenSpecularIndirect *= ambientOcclusion;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometryNormal, geometryViewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness );\n\t#endif\n#endif"; var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif"; - var begin_vertex = "vec3 transformed = vec3( position );"; + var batching_pars_vertex = "#ifdef USE_BATCHING\n\tattribute float batchId;\n\tuniform highp sampler2D batchingTexture;\n\tmat4 getBatchingMatrix( const in float i ) {\n\t\tint size = textureSize( batchingTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( batchingTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( batchingTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( batchingTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( batchingTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; + + var batching_vertex = "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( batchId );\n#endif"; + + var begin_vertex = "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = vec3( position );\n#endif"; var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif"; - var bsdfs = "vec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( V * D );\n}\n#ifdef USE_IRIDESCENCE\n\tvec3 BRDF_GGX_Iridescence( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 f0, const in float f90, const in float iridescence, const in vec3 iridescenceFresnel, const in float roughness ) {\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = mix( F_Schlick( f0, f90, dotVH ), iridescenceFresnel, iridescence );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif"; + var bsdfs = "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, 1.0, dotVH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n} // validated"; - var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\t return vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat R21 = R12;\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; + var iridescence_fragment = "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, -0.9692660, 0.0556434,\n\t\t-1.5371385, 1.8760108, -0.2040259,\n\t\t-0.4985314, 0.0415560, 1.0572252\n\t);\n\tvec3 Fresnel0ToIor( vec3 fresnel0 ) {\n\t\tvec3 sqrtF0 = sqrt( fresnel0 );\n\t\treturn ( vec3( 1.0 ) + sqrtF0 ) / ( vec3( 1.0 ) - sqrtF0 );\n\t}\n\tvec3 IorToFresnel0( vec3 transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - vec3( incidentIor ) ) / ( transmittedIor + vec3( incidentIor ) ) );\n\t}\n\tfloat IorToFresnel0( float transmittedIor, float incidentIor ) {\n\t\treturn pow2( ( transmittedIor - incidentIor ) / ( transmittedIor + incidentIor ));\n\t}\n\tvec3 evalSensitivity( float OPD, vec3 shift ) {\n\t\tfloat phase = 2.0 * PI * OPD * 1.0e-9;\n\t\tvec3 val = vec3( 5.4856e-13, 4.4201e-13, 5.2481e-13 );\n\t\tvec3 pos = vec3( 1.6810e+06, 1.7953e+06, 2.2084e+06 );\n\t\tvec3 var = vec3( 4.3278e+09, 9.3046e+09, 6.6121e+09 );\n\t\tvec3 xyz = val * sqrt( 2.0 * PI * var ) * cos( pos * phase + shift ) * exp( - pow2( phase ) * var );\n\t\txyz.x += 9.7470e-14 * sqrt( 2.0 * PI * 4.5282e+09 ) * cos( 2.2399e+06 * phase + shift[ 0 ] ) * exp( - 4.5282e+09 * pow2( phase ) );\n\t\txyz /= 1.0685e-7;\n\t\tvec3 rgb = XYZ_TO_REC709 * xyz;\n\t\treturn rgb;\n\t}\n\tvec3 evalIridescence( float outsideIOR, float eta2, float cosTheta1, float thinFilmThickness, vec3 baseF0 ) {\n\t\tvec3 I;\n\t\tfloat iridescenceIOR = mix( outsideIOR, eta2, smoothstep( 0.0, 0.03, thinFilmThickness ) );\n\t\tfloat sinTheta2Sq = pow2( outsideIOR / iridescenceIOR ) * ( 1.0 - pow2( cosTheta1 ) );\n\t\tfloat cosTheta2Sq = 1.0 - sinTheta2Sq;\n\t\tif ( cosTheta2Sq < 0.0 ) {\n\t\t\treturn vec3( 1.0 );\n\t\t}\n\t\tfloat cosTheta2 = sqrt( cosTheta2Sq );\n\t\tfloat R0 = IorToFresnel0( iridescenceIOR, outsideIOR );\n\t\tfloat R12 = F_Schlick( R0, 1.0, cosTheta1 );\n\t\tfloat T121 = 1.0 - R12;\n\t\tfloat phi12 = 0.0;\n\t\tif ( iridescenceIOR < outsideIOR ) phi12 = PI;\n\t\tfloat phi21 = PI - phi12;\n\t\tvec3 baseIOR = Fresnel0ToIor( clamp( baseF0, 0.0, 0.9999 ) );\t\tvec3 R1 = IorToFresnel0( baseIOR, iridescenceIOR );\n\t\tvec3 R23 = F_Schlick( R1, 1.0, cosTheta2 );\n\t\tvec3 phi23 = vec3( 0.0 );\n\t\tif ( baseIOR[ 0 ] < iridescenceIOR ) phi23[ 0 ] = PI;\n\t\tif ( baseIOR[ 1 ] < iridescenceIOR ) phi23[ 1 ] = PI;\n\t\tif ( baseIOR[ 2 ] < iridescenceIOR ) phi23[ 2 ] = PI;\n\t\tfloat OPD = 2.0 * iridescenceIOR * thinFilmThickness * cosTheta2;\n\t\tvec3 phi = vec3( phi21 ) + phi23;\n\t\tvec3 R123 = clamp( R12 * R23, 1e-5, 0.9999 );\n\t\tvec3 r123 = sqrt( R123 );\n\t\tvec3 Rs = pow2( T121 ) * R23 / ( vec3( 1.0 ) - R123 );\n\t\tvec3 C0 = R12 + Rs;\n\t\tI = C0;\n\t\tvec3 Cm = Rs - T121;\n\t\tfor ( int m = 1; m <= 2; ++ m ) {\n\t\t\tCm *= r123;\n\t\t\tvec3 Sm = 2.0 * evalSensitivity( float( m ) * OPD, float( m ) * phi );\n\t\t\tI += Cm * Sm;\n\t\t}\n\t\treturn max( I, vec3( 0.0 ) );\n\t}\n#endif"; - var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = dFdx( surf_pos.xyz );\n\t\tvec3 vSigmaY = dFdy( surf_pos.xyz );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; + var bumpmap_pars_fragment = "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vBumpMapUv );\n\t\tvec2 dSTdy = dFdy( vBumpMapUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vBumpMapUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vBumpMapUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy, float faceDirection ) {\n\t\tvec3 vSigmaX = normalize( dFdx( surf_pos.xyz ) );\n\t\tvec3 vSigmaY = normalize( dFdy( surf_pos.xyz ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 ) * faceDirection;\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif"; var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif"; @@ -12457,23 +13313,23 @@ var color_vertex = "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor *= color;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif"; - var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}"; + var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\n#define EPSILON 1e-6\n#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement( a ) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nvec3 pow2( const in vec3 x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); }\nfloat average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract( sin( sn ) * c );\n}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\n#ifdef USE_ALPHAHASH\n\tvarying vec3 vPosition;\n#endif\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat luminance( const in vec3 rgb ) {\n\tconst vec3 weights = vec3( 0.2126729, 0.7151522, 0.0721750 );\n\treturn dot( weights, rgb );\n}\nbool isPerspectiveMatrix( mat4 m ) {\n\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}\nvec3 BRDF_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n}\nfloat F_Schlick( const in float f0, const in float f90, const in float dotVH ) {\n\tfloat fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH );\n\treturn f0 * ( 1.0 - fresnel ) + ( f90 * fresnel );\n} // validated"; - var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_v0 0.339\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_v1 0.276\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_v4 0.046\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_v5 0.016\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_v6 0.0038\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; + var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\thighp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tuv.x += filterInt * 3.0 * cubeUV_minTileSize;\n\t\tuv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize );\n\t\tuv.x *= CUBEUV_TEXEL_WIDTH;\n\t\tuv.y *= CUBEUV_TEXEL_HEIGHT;\n\t\t#ifdef texture2DGradEXT\n\t\t\treturn texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb;\n\t\t#else\n\t\t\treturn texture2D( envMap, uv ).rgb;\n\t\t#endif\n\t}\n\t#define cubeUV_r0 1.0\n\t#define cubeUV_m0 - 2.0\n\t#define cubeUV_r1 0.8\n\t#define cubeUV_m1 - 1.0\n\t#define cubeUV_r4 0.4\n\t#define cubeUV_m4 2.0\n\t#define cubeUV_r5 0.305\n\t#define cubeUV_m5 3.0\n\t#define cubeUV_r6 0.21\n\t#define cubeUV_m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= cubeUV_r1 ) {\n\t\t\tmip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0;\n\t\t} else if ( roughness >= cubeUV_r4 ) {\n\t\t\tmip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1;\n\t\t} else if ( roughness >= cubeUV_r5 ) {\n\t\t\tmip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4;\n\t\t} else if ( roughness >= cubeUV_r6 ) {\n\t\t\tmip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif"; - var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; + var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = objectTangent;\n#endif\n#ifdef USE_BATCHING\n\tmat3 bm = mat3( batchingMatrix );\n\ttransformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) );\n\ttransformedNormal = bm * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = bm * transformedTangent;\n\t#endif\n#endif\n#ifdef USE_INSTANCING\n\tmat3 im = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) );\n\ttransformedNormal = im * transformedNormal;\n\t#ifdef USE_TANGENT\n\t\ttransformedTangent = im * transformedTangent;\n\t#endif\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\ttransformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif"; var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif"; - var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif"; + var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\n#endif"; - var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; + var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif"; var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"; - var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; + var colorspace_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );"; - var encodings_pars_fragment = "vec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}"; + var colorspace_pars_fragment = "\nconst mat3 LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = mat3(\n\tvec3( 0.8224621, 0.177538, 0.0 ),\n\tvec3( 0.0331941, 0.9668058, 0.0 ),\n\tvec3( 0.0170827, 0.0723974, 0.9105199 )\n);\nconst mat3 LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.2249401, - 0.2249404, 0.0 ),\n\tvec3( - 0.0420569, 1.0420571, 0.0 ),\n\tvec3( - 0.0196376, - 0.0786361, 1.0982735 )\n);\nvec4 LinearSRGBToLinearDisplayP3( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_SRGB_TO_LINEAR_DISPLAY_P3, value.a );\n}\nvec4 LinearDisplayP3ToLinearSRGB( in vec4 value ) {\n\treturn vec4( value.rgb * LINEAR_DISPLAY_P3_TO_LINEAR_SRGB, value.a );\n}\nvec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTransferOETF( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn sRGBTransferOETF( value );\n}"; var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif"; @@ -12495,35 +13351,35 @@ var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn vec3( texture2D( gradientMap, coord ).r );\n\t#else\n\t\tvec2 fw = fwidth( coord ) * 0.5;\n\t\treturn mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) );\n\t#endif\n}"; - var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; + var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\treflectedLight.indirectDiffuse += lightMapIrradiance;\n#endif"; var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif"; var lights_lambert_fragment = "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularStrength = specularStrength;"; - var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in GeometricContext geometry, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; + var lights_lambert_pars_fragment = "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\n\tfloat specularStrength;\n};\nvoid RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Lambert\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Lambert"; - var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#else\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; + var lights_pars_begin = "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( USE_LIGHT_PROBES )\n\tuniform vec3 lightProbe[ 9 ];\n#endif\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) {\n\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\treturn irradiance;\n}\nfloat getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n\t#if defined ( LEGACY_LIGHTS )\n\t\tif ( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\t\treturn pow( saturate( - lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t\t}\n\t\treturn 1.0;\n\t#else\n\t\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\t\tif ( cutoffDistance > 0.0 ) {\n\t\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t\t}\n\t\treturn distanceFalloff;\n\t#endif\n}\nfloat getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) {\n\treturn smoothstep( coneCosine, penumbraCosine, angleCosine );\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) {\n\t\tlight.color = directionalLight.color;\n\t\tlight.direction = directionalLight.direction;\n\t\tlight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = pointLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tlight.color = pointLight.color;\n\t\tlight.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay );\n\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) {\n\t\tvec3 lVector = spotLight.position - geometryPosition;\n\t\tlight.direction = normalize( lVector );\n\t\tfloat angleCos = dot( light.direction, spotLight.direction );\n\t\tfloat spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\tif ( spotAttenuation > 0.0 ) {\n\t\t\tfloat lightDistance = length( lVector );\n\t\t\tlight.color = spotLight.color * spotAttenuation;\n\t\t\tlight.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tlight.visible = ( light.color != vec3( 0.0 ) );\n\t\t} else {\n\t\t\tlight.color = vec3( 0.0 );\n\t\t\tlight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) {\n\t\tfloat dotNL = dot( normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\treturn irradiance;\n\t}\n#endif"; - var envmap_physical_pars_fragment = "#if defined( USE_ENVMAP )\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#if defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n#endif"; + var envmap_physical_pars_fragment = "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 1.0 );\n\t\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\tvec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) {\n\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\tvec3 reflectVec = reflect( - viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t\treturn envMapColor.rgb * envMapIntensity;\n\t\t#else\n\t\t\treturn vec3( 0.0 );\n\t\t#endif\n\t}\n\t#ifdef USE_ANISOTROPY\n\t\tvec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) {\n\t\t\t#ifdef ENVMAP_TYPE_CUBE_UV\n\t\t\t\tvec3 bentNormal = cross( bitangent, viewDir );\n\t\t\t\tbentNormal = normalize( cross( bentNormal, bitangent ) );\n\t\t\t\tbentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) );\n\t\t\t\treturn getIBLRadiance( viewDir, bentNormal, roughness );\n\t\t\t#else\n\t\t\t\treturn vec3( 0.0 );\n\t\t\t#endif\n\t\t}\n\t#endif\n#endif"; var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"; - var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; + var lights_toon_pars_fragment = "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon"; var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;"; - var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; + var lights_phong_pars_fragment = "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong"; - var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULARINTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vUv ).a;\n\t\t#endif\n\t\t#ifdef USE_SPECULARCOLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vUv ).rgb;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vUv ).a;\n\t#endif\n#endif"; + var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness;\nmaterial.roughness = min( material.roughness, 1.0 );\n#ifdef IOR\n\tmaterial.ior = ior;\n\t#ifdef USE_SPECULAR\n\t\tfloat specularIntensityFactor = specularIntensity;\n\t\tvec3 specularColorFactor = specularColor;\n\t\t#ifdef USE_SPECULAR_COLORMAP\n\t\t\tspecularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb;\n\t\t#endif\n\t\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\t\tspecularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a;\n\t\t#endif\n\t\tmaterial.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor );\n\t#else\n\t\tfloat specularIntensityFactor = 1.0;\n\t\tvec3 specularColorFactor = vec3( 1.0 );\n\t\tmaterial.specularF90 = 1.0;\n\t#endif\n\tmaterial.specularColor = mix( min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor, diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( 0.04 ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.specularF90 = 1.0;\n#endif\n#ifdef USE_CLEARCOAT\n\tmaterial.clearcoat = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\tmaterial.clearcoatF0 = vec3( 0.04 );\n\tmaterial.clearcoatF90 = 1.0;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_IRIDESCENCE\n\tmaterial.iridescence = iridescence;\n\tmaterial.iridescenceIOR = iridescenceIOR;\n\t#ifdef USE_IRIDESCENCEMAP\n\t\tmaterial.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r;\n\t#endif\n\t#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\t\tmaterial.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum;\n\t#else\n\t\tmaterial.iridescenceThickness = iridescenceThicknessMaximum;\n\t#endif\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheenColor;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tmaterial.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb;\n\t#endif\n\tmaterial.sheenRoughness = clamp( sheenRoughness, 0.07, 1.0 );\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tmaterial.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\t#ifdef USE_ANISOTROPYMAP\n\t\tmat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x );\n\t\tvec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb;\n\t\tvec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b;\n\t#else\n\t\tvec2 anisotropyV = anisotropyVector;\n\t#endif\n\tmaterial.anisotropy = length( anisotropyV );\n\tif( material.anisotropy == 0.0 ) {\n\t\tanisotropyV = vec2( 1.0, 0.0 );\n\t} else {\n\t\tanisotropyV /= material.anisotropy;\n\t\tmaterial.anisotropy = saturate( material.anisotropy );\n\t}\n\tmaterial.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) );\n\tmaterial.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y;\n\tmaterial.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y;\n#endif"; - var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n};\nvec3 clearcoatSpecular = vec3( 0.0 );\nvec3 sheenSpecular = vec3( 0.0 );\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecular += ccIrradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.clearcoatNormal, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * BRDF_Sheen( directLight.direction, geometry.viewDir, geometry.normal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX_Iridescence( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness );\n\t#else\n\t\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometry.viewDir, geometry.normal, material.specularColor, material.specularF90, material.roughness );\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecular += clearcoatRadiance * EnvironmentBRDF( geometry.clearcoatNormal, geometry.viewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecular += irradiance * material.sheenColor * IBLSheenBRDF( geometry.normal, geometry.viewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometry.normal, geometry.viewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; + var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 specularColor;\n\tfloat specularF90;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat clearcoat;\n\t\tfloat clearcoatRoughness;\n\t\tvec3 clearcoatF0;\n\t\tfloat clearcoatF90;\n\t#endif\n\t#ifdef USE_IRIDESCENCE\n\t\tfloat iridescence;\n\t\tfloat iridescenceIOR;\n\t\tfloat iridescenceThickness;\n\t\tvec3 iridescenceFresnel;\n\t\tvec3 iridescenceF0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tvec3 sheenColor;\n\t\tfloat sheenRoughness;\n\t#endif\n\t#ifdef IOR\n\t\tfloat ior;\n\t#endif\n\t#ifdef USE_TRANSMISSION\n\t\tfloat transmission;\n\t\tfloat transmissionAlpha;\n\t\tfloat thickness;\n\t\tfloat attenuationDistance;\n\t\tvec3 attenuationColor;\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat anisotropy;\n\t\tfloat alphaT;\n\t\tvec3 anisotropyT;\n\t\tvec3 anisotropyB;\n\t#endif\n};\nvec3 clearcoatSpecularDirect = vec3( 0.0 );\nvec3 clearcoatSpecularIndirect = vec3( 0.0 );\nvec3 sheenSpecularDirect = vec3( 0.0 );\nvec3 sheenSpecularIndirect = vec3(0.0 );\nvec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) {\n float x = clamp( 1.0 - dotVH, 0.0, 1.0 );\n float x2 = x * x;\n float x5 = clamp( x * x2 * x2, 0.0, 0.9999 );\n return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 );\n}\nfloat V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\n#ifdef USE_ANISOTROPY\n\tfloat V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) {\n\t\tfloat gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) );\n\t\tfloat gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) );\n\t\tfloat v = 0.5 / ( gv + gl );\n\t\treturn saturate(v);\n\t}\n\tfloat D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) {\n\t\tfloat a2 = alphaT * alphaB;\n\t\thighp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH );\n\t\thighp float v2 = dot( v, v );\n\t\tfloat w2 = a2 / v2;\n\t\treturn RECIPROCAL_PI * a2 * pow2 ( w2 );\n\t}\n#endif\n#ifdef USE_CLEARCOAT\n\tvec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) {\n\t\tvec3 f0 = material.clearcoatF0;\n\t\tfloat f90 = material.clearcoatF90;\n\t\tfloat roughness = material.clearcoatRoughness;\n\t\tfloat alpha = pow2( roughness );\n\t\tvec3 halfDir = normalize( lightDir + viewDir );\n\t\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\t\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\t\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\t\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\t\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t\treturn F * ( V * D );\n\t}\n#endif\nvec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) {\n\tvec3 f0 = material.specularColor;\n\tfloat f90 = material.specularF90;\n\tfloat roughness = material.roughness;\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat dotVH = saturate( dot( viewDir, halfDir ) );\n\tvec3 F = F_Schlick( f0, f90, dotVH );\n\t#ifdef USE_IRIDESCENCE\n\t\tF = mix( F, material.iridescenceFresnel, material.iridescence );\n\t#endif\n\t#ifdef USE_ANISOTROPY\n\t\tfloat dotTL = dot( material.anisotropyT, lightDir );\n\t\tfloat dotTV = dot( material.anisotropyT, viewDir );\n\t\tfloat dotTH = dot( material.anisotropyT, halfDir );\n\t\tfloat dotBL = dot( material.anisotropyB, lightDir );\n\t\tfloat dotBV = dot( material.anisotropyB, viewDir );\n\t\tfloat dotBH = dot( material.anisotropyB, halfDir );\n\t\tfloat V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL );\n\t\tfloat D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH );\n\t#else\n\t\tfloat V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\t\tfloat D = D_GGX( alpha, dotNH );\n\t#endif\n\treturn F * ( V * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\n#if defined( USE_SHEEN )\nfloat D_Charlie( float roughness, float dotNH ) {\n\tfloat alpha = pow2( roughness );\n\tfloat invAlpha = 1.0 / alpha;\n\tfloat cos2h = dotNH * dotNH;\n\tfloat sin2h = max( 1.0 - cos2h, 0.0078125 );\n\treturn ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI );\n}\nfloat V_Neubelt( float dotNV, float dotNL ) {\n\treturn saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) );\n}\nvec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) {\n\tvec3 halfDir = normalize( lightDir + viewDir );\n\tfloat dotNL = saturate( dot( normal, lightDir ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( normal, halfDir ) );\n\tfloat D = D_Charlie( sheenRoughness, dotNH );\n\tfloat V = V_Neubelt( dotNV, dotNL );\n\treturn sheenColor * ( D * V );\n}\n#endif\nfloat IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat r2 = roughness * roughness;\n\tfloat a = roughness < 0.25 ? -339.2 * r2 + 161.4 * roughness - 25.9 : -8.48 * r2 + 14.3 * roughness - 9.95;\n\tfloat b = roughness < 0.25 ? 44.0 * r2 - 23.7 * roughness + 3.26 : 1.97 * r2 - 3.27 * roughness + 0.72;\n\tfloat DG = exp( a * dotNV + b ) + ( roughness < 0.25 ? 0.0 : 0.1 * ( roughness - 0.25 ) );\n\treturn saturate( DG * RECIPROCAL_PI );\n}\nvec2 DFGApprox( const in vec3 normal, const in vec3 viewDir, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 fab = vec2( - 1.04, 1.04 ) * a004 + r.zw;\n\treturn fab;\n}\nvec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) {\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\treturn specularColor * fab.x + specularF90 * fab.y;\n}\n#ifdef USE_IRIDESCENCE\nvoid computeMultiscatteringIridescence( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#else\nvoid computeMultiscattering( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n#endif\n\tvec2 fab = DFGApprox( normal, viewDir, roughness );\n\t#ifdef USE_IRIDESCENCE\n\t\tvec3 Fr = mix( specularColor, iridescenceF0, iridescence );\n\t#else\n\t\tvec3 Fr = specularColor;\n\t#endif\n\tvec3 FssEss = Fr * fab.x + specularF90 * fab.y;\n\tfloat Ess = fab.x + fab.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometryNormal;\n\t\tvec3 viewDir = geometryViewDir;\n\t\tvec3 position = geometryPosition;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.roughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometryNormal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = dotNLcc * directLight.color;\n\t\tclearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness );\n\t#endif\n\treflectedLight.directSpecular += irradiance * BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material );\n\treflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness );\n\t#endif\n\t#ifdef USE_SHEEN\n\t\tsheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness );\n\t#endif\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\t#ifdef USE_IRIDESCENCE\n\t\tcomputeMultiscatteringIridescence( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.iridescence, material.iridescenceFresnel, material.roughness, singleScattering, multiScattering );\n\t#else\n\t\tcomputeMultiscattering( geometryNormal, geometryViewDir, material.specularColor, material.specularF90, material.roughness, singleScattering, multiScattering );\n\t#endif\n\tvec3 totalScattering = singleScattering + multiScattering;\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - max( max( totalScattering.r, totalScattering.g ), totalScattering.b ) );\n\treflectedLight.indirectSpecular += radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}"; - var lights_fragment_begin = "\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef USE_CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometry.viewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometry, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, geometry, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry.normal );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry.normal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; + var lights_fragment_begin = "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nvec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\nvec3 geometryClearcoatNormal = vec3( 0.0 );\n#ifdef USE_CLEARCOAT\n\tgeometryClearcoatNormal = clearcoatNormal;\n#endif\n#ifdef USE_IRIDESCENCE\n\tfloat dotNVi = saturate( dot( normal, geometryViewDir ) );\n\tif ( material.iridescenceThickness == 0.0 ) {\n\t\tmaterial.iridescence = 0.0;\n\t} else {\n\t\tmaterial.iridescence = saturate( material.iridescence );\n\t}\n\tif ( material.iridescence > 0.0 ) {\n\t\tmaterial.iridescenceFresnel = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor );\n\t\tmaterial.iridescenceF0 = Schlick_to_F0( material.iridescenceFresnel, 1.0, dotNVi );\n\t}\n#endif\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointLightInfo( pointLight, geometryPosition, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\tvec4 spotColor;\n\tvec3 spotLightCoord;\n\tbool inSpotLightMap;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotLightInfo( spotLight, geometryPosition, directLight );\n\t\t#if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX\n\t\t#elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t#define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS\n\t\t#else\n\t\t#define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS )\n\t\t#endif\n\t\t#if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS )\n\t\t\tspotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w;\n\t\t\tinSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) );\n\t\t\tspotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy );\n\t\t\tdirectLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color;\n\t\t#endif\n\t\t#undef SPOT_LIGHT_MAP_INDEX\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalLightInfo( directionalLight, directLight );\n\t\t#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if defined( USE_LIGHT_PROBES )\n\t\tirradiance += getLightProbeIrradiance( lightProbe, geometryNormal );\n\t#endif\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif"; - var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometry.normal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getIBLRadiance( geometry.viewDir, geometry.normal, material.roughness );\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; + var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\tvec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity;\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getIBLIrradiance( geometryNormal );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\t#ifdef USE_ANISOTROPY\n\t\tradiance += getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy );\n\t#else\n\t\tradiance += getIBLRadiance( geometryViewDir, geometryNormal, material.roughness );\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tclearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness );\n\t#endif\n#endif"; - var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif"; + var lights_fragment_end = "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight );\n#endif"; var logdepthbuf_fragment = "#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif"; @@ -12533,15 +13389,15 @@ var logdepthbuf_vertex = "#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\n\t#endif\n#endif"; - var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; + var map_fragment = "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\tsampledDiffuseColor = vec4( mix( pow( sampledDiffuseColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), sampledDiffuseColor.rgb * 0.0773993808, vec3( lessThanEqual( sampledDiffuseColor.rgb, vec3( 0.04045 ) ) ) ), sampledDiffuseColor.w );\n\t\n\t#endif\n\tdiffuseColor *= sampledDiffuseColor;\n#endif"; var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"; - var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; + var map_particle_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t#if defined( USE_POINTS_UV )\n\t\tvec2 uv = vUv;\n\t#else\n\t\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tdiffuseColor *= texture2D( map, uv );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif"; - var map_particle_pars_fragment = "#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; + var map_particle_pars_fragment = "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\t\tuniform mat3 uvTransform;\n\t#endif\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"; - var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; + var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif"; var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"; @@ -12553,9 +13409,9 @@ var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\t#ifdef MORPHTARGETS_TEXTURE\n\t\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\n\t\t\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\n\t\t}\n\t#else\n\t\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\t\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\t\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\t\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t\t#ifndef USE_MORPHNORMALS\n\t\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t\t#endif\n\t#endif\n#endif"; - var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * faceDirection;\n\t\t\tbitangent = bitangent * faceDirection;\n\t\t#endif\n\t\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;"; + var normal_fragment_begin = "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tvec3 fdx = dFdx( vViewPosition );\n\tvec3 fdy = dFdy( vViewPosition );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal *= faceDirection;\n\t#endif\n#endif\n#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY )\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn = getTangentFrame( - vViewPosition, normal,\n\t\t#if defined( USE_NORMALMAP )\n\t\t\tvNormalMapUv\n\t\t#elif defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tvClearcoatNormalMapUv\n\t\t#else\n\t\t\tvUv\n\t\t#endif\n\t\t);\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn[0] *= faceDirection;\n\t\ttbn[1] *= faceDirection;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal );\n\t#else\n\t\tmat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv );\n\t#endif\n\t#if defined( DOUBLE_SIDED ) && ! defined( FLAT_SHADED )\n\t\ttbn2[0] *= faceDirection;\n\t\ttbn2[1] *= faceDirection;\n\t#endif\n#endif\nvec3 nonPerturbedNormal = normal;"; - var normal_fragment_maps = "#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( - vViewPosition, normal, mapN, faceDirection );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; + var normal_fragment_maps = "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * faceDirection;\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( USE_NORMALMAP_TANGENTSPACE )\n\tvec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\tnormal = normalize( tbn * mapN );\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection );\n#endif"; var normal_pars_fragment = "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif"; @@ -12563,149 +13419,147 @@ var normal_vertex = "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif"; - var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec3 mapN, float faceDirection ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : faceDirection * inversesqrt( det );\n\t\treturn normalize( T * ( mapN.x * scale ) + B * ( mapN.y * scale ) + N * mapN.z );\n\t}\n#endif"; + var normalmap_pars_fragment = "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n#endif\n#ifdef USE_NORMALMAP_OBJECTSPACE\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) )\n\tmat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) {\n\t\tvec3 q0 = dFdx( eye_pos.xyz );\n\t\tvec3 q1 = dFdy( eye_pos.xyz );\n\t\tvec2 st0 = dFdx( uv.st );\n\t\tvec2 st1 = dFdy( uv.st );\n\t\tvec3 N = surf_norm;\n\t\tvec3 q1perp = cross( q1, N );\n\t\tvec3 q0perp = cross( N, q0 );\n\t\tvec3 T = q1perp * st0.x + q0perp * st1.x;\n\t\tvec3 B = q1perp * st0.y + q0perp * st1.y;\n\t\tfloat det = max( dot( T, T ), dot( B, B ) );\n\t\tfloat scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det );\n\t\treturn mat3( T * scale, B * scale, N );\n\t}\n#endif"; - var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif"; + var clearcoat_normal_fragment_begin = "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"; - var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN, faceDirection );\n\t#endif\n#endif"; + var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\tclearcoatNormal = normalize( tbn2 * clearcoatMapN );\n#endif"; - var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif"; + var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif"; var iridescence_pars_fragment = "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform sampler2D iridescenceThicknessMap;\n#endif"; - var output_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha + 0.1;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; + var opaque_fragment = "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffuseColor.a *= material.transmissionAlpha;\n#endif\ngl_FragColor = vec4( outgoingLight, diffuseColor.a );"; - var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}"; + var packing = "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nvec2 packDepthToRG( in highp float v ) {\n\treturn packDepthToRGBA( v ).yx;\n}\nfloat unpackRGToDepth( const in highp vec2 v ) {\n\treturn unpackRGBAToDepth( vec4( v.xy, 0.0, 0.0 ) );\n}\nvec4 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) );\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w );\n}\nvec2 unpackRGBATo2Half( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn depth * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * depth - far );\n}"; var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"; - var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; + var project_vertex = "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPosition = batchingMatrix * mvPosition;\n#endif\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;"; var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"; var dithering_pars_fragment = "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif"; - var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; + var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\n\troughnessFactor *= texelRoughness.g;\n#endif"; var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"; - var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; + var shadowmap_pars_fragment = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#if NUM_SPOT_LIGHT_MAPS > 0\n\tuniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn unpackRGBATo2Half( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0;\n\t\tbool frustumTest = inFrustum && shadowCoord.z <= 1.0;\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 17.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif"; - var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; + var shadowmap_pars_vertex = "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ];\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ];\n#endif\n#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif"; - var shadowmap_vertex = "#if defined( USE_SHADOWMAP ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_COORDS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif"; + var shadowmap_vertex = "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 )\n\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\tvec4 shadowWorldPosition;\n#endif\n#if defined( USE_SHADOWMAP )\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if NUM_SPOT_LIGHT_COORDS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition;\n\t\t#if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\t\tshadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias;\n\t\t#endif\n\t\tvSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n#endif"; var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}"; var skinbase_vertex = "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif"; - var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tuniform int boneTextureSize;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tfloat j = i * 4.0;\n\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\ty = dy * ( y + 0.5 );\n\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\treturn bone;\n\t}\n#endif"; + var skinning_pars_vertex = "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\tuniform highp sampler2D boneTexture;\n\tmat4 getBoneMatrix( const in float i ) {\n\t\tint size = textureSize( boneTexture, 0 ).x;\n\t\tint j = int( i ) * 4;\n\t\tint x = j % size;\n\t\tint y = j / size;\n\t\tvec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 );\n\t\tvec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 );\n\t\tvec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 );\n\t\tvec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 );\n\t\treturn mat4( v1, v2, v3, v4 );\n\t}\n#endif"; var skinning_vertex = "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif"; var skinnormal_vertex = "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\n#endif"; - var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; + var specularmap_fragment = "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vSpecularMapUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif"; var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"; var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif"; - var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - - var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmission = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmission.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmission.rgb, material.transmission );\n#endif"; - - var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat framebufferLod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\t#ifdef texture2DLodEXT\n\t\t\treturn texture2DLodEXT( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#else\n\t\t\treturn texture2D( transmissionSamplerMap, fragCoord.xy, framebufferLod );\n\t\t#endif\n\t}\n\tvec3 applyVolumeAttenuation( const in vec3 radiance, const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn radiance;\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance * radiance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 attenuatedColor = applyVolumeAttenuation( transmittedLight.rgb, length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor * diffuseColor, transmittedLight.a );\n\t}\n#endif"; + var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn saturate( toneMappingExposure * color );\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nconst mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3(\n\tvec3( 1.6605, - 0.1246, - 0.0182 ),\n\tvec3( - 0.5876, 1.1329, - 0.1006 ),\n\tvec3( - 0.0728, - 0.0083, 1.1187 )\n);\nconst mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3(\n\tvec3( 0.6274, 0.0691, 0.0164 ),\n\tvec3( 0.3293, 0.9195, 0.0880 ),\n\tvec3( 0.0433, 0.0113, 0.8956 )\n);\nvec3 agxDefaultContrastApprox( vec3 x ) {\n\tvec3 x2 = x * x;\n\tvec3 x4 = x2 * x2;\n\treturn + 15.5 * x4 * x2\n\t\t- 40.14 * x4 * x\n\t\t+ 31.96 * x4\n\t\t- 6.868 * x2 * x\n\t\t+ 0.4298 * x2\n\t\t+ 0.1191 * x\n\t\t- 0.00232;\n}\nvec3 AgXToneMapping( vec3 color ) {\n\tconst mat3 AgXInsetMatrix = mat3(\n\t\tvec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ),\n\t\tvec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ),\n\t\tvec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 )\n\t);\n\tconst mat3 AgXOutsetMatrix = mat3(\n\t\tvec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ),\n\t\tvec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ),\n\t\tvec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 )\n\t);\n\tconst float AgxMinEv = - 12.47393;\tconst float AgxMaxEv = 4.026069;\n\tcolor = LINEAR_SRGB_TO_LINEAR_REC2020 * color;\n\tcolor *= toneMappingExposure;\n\tcolor = AgXInsetMatrix * color;\n\tcolor = max( color, 1e-10 );\tcolor = log2( color );\n\tcolor = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv );\n\tcolor = clamp( color, 0.0, 1.0 );\n\tcolor = agxDefaultContrastApprox( color );\n\tcolor = AgXOutsetMatrix * color;\n\tcolor = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) );\n\tcolor = LINEAR_REC2020_TO_LINEAR_SRGB * color;\n\treturn color;\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }"; - var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif"; + var transmission_fragment = "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial.transmissionAlpha = 1.0;\n\tmaterial.thickness = thickness;\n\tmaterial.attenuationDistance = attenuationDistance;\n\tmaterial.attenuationColor = attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tmaterial.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tmaterial.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g;\n\t#endif\n\tvec3 pos = vWorldPosition;\n\tvec3 v = normalize( cameraPosition - pos );\n\tvec3 n = inverseTransformDirection( normal, viewMatrix );\n\tvec4 transmitted = getIBLVolumeRefraction(\n\t\tn, v, material.roughness, material.diffuseColor, material.specularColor, material.specularF90,\n\t\tpos, modelMatrix, viewMatrix, projectionMatrix, material.ior, material.thickness,\n\t\tmaterial.attenuationColor, material.attenuationDistance );\n\tmaterial.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission );\n\ttotalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission );\n#endif"; - var uv_pars_vertex = "#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif"; + var transmission_pars_fragment = "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thickness;\n\tuniform float attenuationDistance;\n\tuniform vec3 attenuationColor;\n\t#ifdef USE_TRANSMISSIONMAP\n\t\tuniform sampler2D transmissionMap;\n\t#endif\n\t#ifdef USE_THICKNESSMAP\n\t\tuniform sampler2D thicknessMap;\n\t#endif\n\tuniform vec2 transmissionSamplerSize;\n\tuniform sampler2D transmissionSamplerMap;\n\tuniform mat4 modelMatrix;\n\tuniform mat4 projectionMatrix;\n\tvarying vec3 vWorldPosition;\n\tfloat w0( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 );\n\t}\n\tfloat w1( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 );\n\t}\n\tfloat w2( float a ){\n\t\treturn ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 );\n\t}\n\tfloat w3( float a ) {\n\t\treturn ( 1.0 / 6.0 ) * ( a * a * a );\n\t}\n\tfloat g0( float a ) {\n\t\treturn w0( a ) + w1( a );\n\t}\n\tfloat g1( float a ) {\n\t\treturn w2( a ) + w3( a );\n\t}\n\tfloat h0( float a ) {\n\t\treturn - 1.0 + w1( a ) / ( w0( a ) + w1( a ) );\n\t}\n\tfloat h1( float a ) {\n\t\treturn 1.0 + w3( a ) / ( w2( a ) + w3( a ) );\n\t}\n\tvec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) {\n\t\tuv = uv * texelSize.zw + 0.5;\n\t\tvec2 iuv = floor( uv );\n\t\tvec2 fuv = fract( uv );\n\t\tfloat g0x = g0( fuv.x );\n\t\tfloat g1x = g1( fuv.x );\n\t\tfloat h0x = h0( fuv.x );\n\t\tfloat h1x = h1( fuv.x );\n\t\tfloat h0y = h0( fuv.y );\n\t\tfloat h1y = h1( fuv.y );\n\t\tvec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\tvec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy;\n\t\treturn g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) +\n\t\t\tg1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) );\n\t}\n\tvec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) {\n\t\tvec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) );\n\t\tvec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) );\n\t\tvec2 fLodSizeInv = 1.0 / fLodSize;\n\t\tvec2 cLodSizeInv = 1.0 / cLodSize;\n\t\tvec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) );\n\t\tvec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) );\n\t\treturn mix( fSample, cSample, fract( lod ) );\n\t}\n\tvec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) {\n\t\tvec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior );\n\t\tvec3 modelScale;\n\t\tmodelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) );\n\t\tmodelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) );\n\t\tmodelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) );\n\t\treturn normalize( refractionVector ) * thickness * modelScale;\n\t}\n\tfloat applyIorToRoughness( const in float roughness, const in float ior ) {\n\t\treturn roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 );\n\t}\n\tvec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) {\n\t\tfloat lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior );\n\t\treturn textureBicubic( transmissionSamplerMap, fragCoord.xy, lod );\n\t}\n\tvec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tif ( isinf( attenuationDistance ) ) {\n\t\t\treturn vec3( 1.0 );\n\t\t} else {\n\t\t\tvec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance;\n\t\t\tvec3 transmittance = exp( - attenuationCoefficient * transmissionDistance );\t\t\treturn transmittance;\n\t\t}\n\t}\n\tvec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor,\n\t\tconst in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix,\n\t\tconst in mat4 viewMatrix, const in mat4 projMatrix, const in float ior, const in float thickness,\n\t\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\n\t\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\n\t\tvec3 refractedRayExit = position + transmissionRay;\n\t\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\n\t\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\n\t\trefractionCoords += 1.0;\n\t\trefractionCoords /= 2.0;\n\t\tvec4 transmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\n\t\tvec3 transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\n\t\tvec3 attenuatedColor = transmittance * transmittedLight.rgb;\n\t\tvec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness );\n\t\tfloat transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0;\n\t\treturn vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor );\n\t}\n#endif"; - var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif"; + var uv_pars_fragment = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif"; + var uv_pars_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#endif\n#ifdef USE_MAP\n\tuniform mat3 mapTransform;\n\tvarying vec2 vMapUv;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform mat3 alphaMapTransform;\n\tvarying vec2 vAlphaMapUv;\n#endif\n#ifdef USE_LIGHTMAP\n\tuniform mat3 lightMapTransform;\n\tvarying vec2 vLightMapUv;\n#endif\n#ifdef USE_AOMAP\n\tuniform mat3 aoMapTransform;\n\tvarying vec2 vAoMapUv;\n#endif\n#ifdef USE_BUMPMAP\n\tuniform mat3 bumpMapTransform;\n\tvarying vec2 vBumpMapUv;\n#endif\n#ifdef USE_NORMALMAP\n\tuniform mat3 normalMapTransform;\n\tvarying vec2 vNormalMapUv;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tuniform mat3 displacementMapTransform;\n\tvarying vec2 vDisplacementMapUv;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tuniform mat3 emissiveMapTransform;\n\tvarying vec2 vEmissiveMapUv;\n#endif\n#ifdef USE_METALNESSMAP\n\tuniform mat3 metalnessMapTransform;\n\tvarying vec2 vMetalnessMapUv;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tuniform mat3 roughnessMapTransform;\n\tvarying vec2 vRoughnessMapUv;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tuniform mat3 anisotropyMapTransform;\n\tvarying vec2 vAnisotropyMapUv;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tuniform mat3 clearcoatMapTransform;\n\tvarying vec2 vClearcoatMapUv;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform mat3 clearcoatNormalMapTransform;\n\tvarying vec2 vClearcoatNormalMapUv;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform mat3 clearcoatRoughnessMapTransform;\n\tvarying vec2 vClearcoatRoughnessMapUv;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tuniform mat3 sheenColorMapTransform;\n\tvarying vec2 vSheenColorMapUv;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tuniform mat3 sheenRoughnessMapTransform;\n\tvarying vec2 vSheenRoughnessMapUv;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tuniform mat3 iridescenceMapTransform;\n\tvarying vec2 vIridescenceMapUv;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tuniform mat3 iridescenceThicknessMapTransform;\n\tvarying vec2 vIridescenceThicknessMapUv;\n#endif\n#ifdef USE_SPECULARMAP\n\tuniform mat3 specularMapTransform;\n\tvarying vec2 vSpecularMapUv;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tuniform mat3 specularColorMapTransform;\n\tvarying vec2 vSpecularColorMapUv;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tuniform mat3 specularIntensityMapTransform;\n\tvarying vec2 vSpecularIntensityMapUv;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tuniform mat3 transmissionMapTransform;\n\tvarying vec2 vTransmissionMapUv;\n#endif\n#ifdef USE_THICKNESSMAP\n\tuniform mat3 thicknessMapTransform;\n\tvarying vec2 vThicknessMapUv;\n#endif"; - var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif"; + var uv_vertex = "#if defined( USE_UV ) || defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 ).xy;\n#endif\n#ifdef USE_MAP\n\tvMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ALPHAMAP\n\tvAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_LIGHTMAP\n\tvLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_AOMAP\n\tvAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_BUMPMAP\n\tvBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_NORMALMAP\n\tvNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_DISPLACEMENTMAP\n\tvDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_EMISSIVEMAP\n\tvEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_METALNESSMAP\n\tvMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ROUGHNESSMAP\n\tvRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_ANISOTROPYMAP\n\tvAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOATMAP\n\tvClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tvClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tvClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCEMAP\n\tvIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\n\tvIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_COLORMAP\n\tvSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SHEEN_ROUGHNESSMAP\n\tvSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULARMAP\n\tvSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_COLORMAP\n\tvSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_SPECULAR_INTENSITYMAP\n\tvSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_TRANSMISSIONMAP\n\tvTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy;\n#endif\n#ifdef USE_THICKNESSMAP\n\tvThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy;\n#endif"; - var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif"; - - var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; + var worldpos_vertex = "#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0\n\tvec4 worldPosition = vec4( transformed, 1.0 );\n\t#ifdef USE_BATCHING\n\t\tworldPosition = batchingMatrix * worldPosition;\n\t#endif\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\n#endif"; const vertex$h = "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}"; - const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$h = "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\t#ifdef DECODE_VIDEO_TEXTURE\n\t\ttexColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$g = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; + const fragment$g = "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMAP_TYPE_CUBE_UV )\n\tuniform sampler2D envMap;\n#endif\nuniform float flipEnvMap;\nuniform float backgroundBlurriness;\nuniform float backgroundIntensity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 texColor = textureCube( envMap, vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\n\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\tvec4 texColor = textureCubeUV( envMap, vWorldDirection, backgroundBlurriness );\n\t#else\n\t\tvec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 );\n\t#endif\n\ttexColor.rgb *= backgroundIntensity;\n\tgl_FragColor = texColor;\n\t#include \n\t#include \n}"; const vertex$f = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}"; - const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; + const fragment$f = "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = texColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}"; - const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; + const vertex$e = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvHighPrecisionZW = gl_Position.zw;\n}"; - const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; + const fragment$e = "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}"; - const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; + const vertex$d = "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}"; - const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; + const fragment$d = "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}"; const vertex$c = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}"; - const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; + const fragment$c = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tgl_FragColor = texture2D( tEquirect, sampleUV );\n\t#include \n\t#include \n}"; - const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$b = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$b = "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$a = "#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if defined ( USE_ENVMAP ) || defined ( USE_SKINNING )\n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$a = "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel = texture2D( lightMap, vLightMapUv );\n\t\treflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$9 = "#define LAMBERT\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$9 = "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; + const vertex$8 = "#define MATCAP\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n}"; - const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$8 = "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t#else\n\t\tvec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; + const vertex$7 = "#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}"; - const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; + const fragment$7 = "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\n\tvarying vec3 vViewPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n\t#ifdef OPAQUE\n\t\tgl_FragColor.a = 1.0;\n\t#endif\n}"; - const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$6 = "#define PHONG\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$6 = "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; + const vertex$5 = "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tvarying vec3 vWorldPosition;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n#ifdef USE_TRANSMISSION\n\tvWorldPosition = worldPosition.xyz;\n#endif\n}"; - const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULARINTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n\t#ifdef USE_SPECULARCOLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEENCOLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEENROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecular;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + clearcoatSpecular * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$5 = "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef IOR\n\tuniform float ior;\n#endif\n#ifdef USE_SPECULAR\n\tuniform float specularIntensity;\n\tuniform vec3 specularColor;\n\t#ifdef USE_SPECULAR_COLORMAP\n\t\tuniform sampler2D specularColorMap;\n\t#endif\n\t#ifdef USE_SPECULAR_INTENSITYMAP\n\t\tuniform sampler2D specularIntensityMap;\n\t#endif\n#endif\n#ifdef USE_CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_IRIDESCENCE\n\tuniform float iridescence;\n\tuniform float iridescenceIOR;\n\tuniform float iridescenceThicknessMinimum;\n\tuniform float iridescenceThicknessMaximum;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheenColor;\n\tuniform float sheenRoughness;\n\t#ifdef USE_SHEEN_COLORMAP\n\t\tuniform sampler2D sheenColorMap;\n\t#endif\n\t#ifdef USE_SHEEN_ROUGHNESSMAP\n\t\tuniform sampler2D sheenRoughnessMap;\n\t#endif\n#endif\n#ifdef USE_ANISOTROPY\n\tuniform vec2 anisotropyVector;\n\t#ifdef USE_ANISOTROPYMAP\n\t\tuniform sampler2D anisotropyMap;\n\t#endif\n#endif\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse;\n\tvec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular;\n\t#include \n\tvec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance;\n\t#ifdef USE_SHEEN\n\t\tfloat sheenEnergyComp = 1.0 - 0.157 * max3( material.sheenColor );\n\t\toutgoingLight = outgoingLight * sheenEnergyComp + sheenSpecularDirect + sheenSpecularIndirect;\n\t#endif\n\t#ifdef USE_CLEARCOAT\n\t\tfloat dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) );\n\t\tvec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc );\n\t\toutgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; + const vertex$4 = "#define TOON\nvarying vec3 vViewPosition;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$4 = "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$3 = "uniform float size;\nuniform float scale;\n#include \n#include \n#include \n#include \n#include \n#include \n#ifdef USE_POINTS_UV\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif\nvoid main() {\n\t#ifdef USE_POINTS_UV\n\t\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$3 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const vertex$2 = "#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const vertex$2 = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}"; - const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; + const fragment$2 = "uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n\t#include \n\t#include \n}"; const vertex$1 = "uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"; - const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; + const fragment$1 = "uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\t#include \n\t#include \n\t#include \n\t#include \n}"; 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, @@ -12726,8 +13580,8 @@ displacementmap_vertex: displacementmap_vertex, emissivemap_fragment: emissivemap_fragment, emissivemap_pars_fragment: emissivemap_pars_fragment, - encodings_fragment: encodings_fragment, - encodings_pars_fragment: encodings_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, @@ -12777,7 +13631,7 @@ clearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps, clearcoat_pars_fragment: clearcoat_pars_fragment, iridescence_pars_fragment: iridescence_pars_fragment, - output_fragment: output_fragment, + opaque_fragment: opaque_fragment, packing: packing, premultiplied_alpha_fragment: premultiplied_alpha_fragment, project_vertex: project_vertex, @@ -12802,9 +13656,6 @@ uv_pars_fragment: uv_pars_fragment, uv_pars_vertex: uv_pars_vertex, uv_vertex: uv_vertex, - uv2_pars_fragment: uv2_pars_fragment, - uv2_pars_vertex: uv2_pars_vertex, - uv2_vertex: uv2_vertex, worldpos_vertex: worldpos_vertex, background_vert: vertex$h, @@ -12855,10 +13706,11 @@ opacity: { value: 1.0 }, map: { value: null }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() }, - uv2Transform: { value: /*@__PURE__*/ new Matrix3() }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } }, @@ -12866,6 +13718,7 @@ specularmap: { specularMap: { value: null }, + specularMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -12882,26 +13735,23 @@ aomap: { aoMap: { value: null }, - aoMapIntensity: { value: 1 } + aoMapIntensity: { value: 1 }, + aoMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, lightmap: { lightMap: { value: null }, - lightMapIntensity: { value: 1 } - - }, - - emissivemap: { - - emissiveMap: { value: null } + lightMapIntensity: { value: 1 }, + lightMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, bumpmap: { bumpMap: { value: null }, + bumpMapTransform: { value: /*@__PURE__*/ new Matrix3() }, bumpScale: { value: 1 } }, @@ -12909,6 +13759,7 @@ normalmap: { normalMap: { value: null }, + normalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, normalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) } }, @@ -12916,20 +13767,30 @@ displacementmap: { displacementMap: { value: null }, + displacementMapTransform: { value: /*@__PURE__*/ new Matrix3() }, displacementScale: { value: 1 }, displacementBias: { value: 0 } }, - roughnessmap: { + emissivemap: { - roughnessMap: { value: null } + emissiveMap: { value: null }, + emissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, metalnessmap: { - metalnessMap: { value: null } + metalnessMap: { value: null }, + metalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } + + }, + + roughnessmap: { + + roughnessMap: { value: null }, + roughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() } }, @@ -13036,6 +13897,7 @@ scale: { value: 1.0 }, map: { value: null }, alphaMap: { value: null }, + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaTest: { value: 0 }, uvTransform: { value: /*@__PURE__*/ new Matrix3() } @@ -13048,9 +13910,10 @@ center: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) }, rotation: { value: 0.0 }, map: { value: null }, + mapTransform: { value: /*@__PURE__*/ new Matrix3() }, alphaMap: { value: null }, - alphaTest: { value: 0 }, - uvTransform: { value: /*@__PURE__*/ new Matrix3() } + alphaMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + alphaTest: { value: 0 } } @@ -13356,33 +14219,47 @@ { clearcoat: { value: 0 }, clearcoatMap: { value: null }, + clearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalMap: { value: null }, + clearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, clearcoatRoughness: { value: 0 }, clearcoatRoughnessMap: { value: null }, - clearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }, - clearcoatNormalMap: { value: null }, + clearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescence: { value: 0 }, iridescenceMap: { value: null }, + iridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() }, iridescenceIOR: { value: 1.3 }, iridescenceThicknessMinimum: { value: 100 }, iridescenceThicknessMaximum: { value: 400 }, iridescenceThicknessMap: { value: null }, + iridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheen: { value: 0 }, sheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, sheenColorMap: { value: null }, + sheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, sheenRoughness: { value: 1 }, sheenRoughnessMap: { value: null }, + sheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmission: { value: 0 }, transmissionMap: { value: null }, + transmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() }, transmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() }, transmissionSamplerMap: { value: null }, thickness: { value: 0 }, thicknessMap: { value: null }, + thicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() }, attenuationDistance: { value: 0 }, attenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) }, - specularIntensity: { value: 1 }, - specularIntensityMap: { value: null }, specularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) }, specularColorMap: { value: null }, + specularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + specularIntensity: { value: 1 }, + specularIntensityMap: { value: null }, + specularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() }, + anisotropyVector: { value: /*@__PURE__*/ new Vector2() }, + anisotropyMap: { value: null }, + anisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() }, } ] ), @@ -13417,26 +14294,26 @@ } - // Ignore background in AR - // TODO: Reconsider this. + if ( background === null ) { - const xr = renderer.xr; - const session = xr.getSession && xr.getSession(); + setClear( clearColor, clearAlpha ); - if ( session && session.environmentBlendMode === 'additive' ) { + } else if ( background && background.isColor ) { - background = null; + setClear( background, 1 ); + forceClear = true; } - if ( background === null ) { + const environmentBlendMode = renderer.xr.getEnvironmentBlendMode(); - setClear( clearColor, clearAlpha ); + if ( environmentBlendMode === 'additive' ) { - } else if ( background && background.isColor ) { + state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha ); - setClear( background, 1 ); - forceClear = true; + } else if ( environmentBlendMode === 'alpha-blend' ) { + + state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha ); } @@ -13492,6 +14369,7 @@ 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.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( currentBackground !== background || currentBackgroundVersion !== background.version || @@ -13547,6 +14425,7 @@ planeMesh.material.uniforms.t2D.value = background; planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity; + planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer; if ( background.matrixAutoUpdate === true ) { @@ -13618,7 +14497,7 @@ function WebGLBindingStates( gl, extensions, attributes, capabilities ) { - const maxVertexAttributes = gl.getParameter( 34921 ); + const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); const extension = capabilities.isWebGL2 ? null : extensions.get( 'OES_vertex_array_object' ); const vaoAvailable = capabilities.isWebGL2 || extension !== null; @@ -13668,7 +14547,7 @@ if ( index !== null ) { - attributes.update( index, 34963 ); + attributes.update( index, gl.ELEMENT_ARRAY_BUFFER ); } @@ -13680,7 +14559,7 @@ if ( index !== null ) { - gl.bindBuffer( 34963, attributes.get( index ).buffer ); + gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer ); } @@ -13933,9 +14812,9 @@ } - function vertexAttribPointer( index, size, type, normalized, stride, offset ) { + function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) { - if ( capabilities.isWebGL2 === true && ( type === 5124 || type === 5125 ) ) { + if ( integer === true ) { gl.vertexAttribIPointer( index, size, type, stride, offset ); @@ -13993,6 +14872,10 @@ const type = attribute.type; const bytesPerElement = attribute.bytesPerElement; + // check for integer attributes (WebGL 2 only) + + const integer = ( capabilities.isWebGL2 === true && ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType ) ); + if ( geometryAttribute.isInterleavedBufferAttribute ) { const data = geometryAttribute.data; @@ -14023,7 +14906,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14033,7 +14916,8 @@ type, normalized, stride * bytesPerElement, - ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement + ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement, + integer ); } @@ -14064,7 +14948,7 @@ } - gl.bindBuffer( 34962, buffer ); + gl.bindBuffer( gl.ARRAY_BUFFER, buffer ); for ( let i = 0; i < programAttribute.locationSize; i ++ ) { @@ -14074,7 +14958,8 @@ type, normalized, size * bytesPerElement, - ( size / programAttribute.locationSize ) * i * bytesPerElement + ( size / programAttribute.locationSize ) * i * bytesPerElement, + integer ); } @@ -14288,11 +15173,42 @@ } + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ], counts[ i ] ); + + } + + } else { + + extension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount ); + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( elementCount, mode, 1 ); + + } + + } + // this.setMode = setMode; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -14324,8 +15240,8 @@ if ( precision === 'highp' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36338 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36338 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) { return 'highp'; @@ -14337,8 +15253,8 @@ if ( precision === 'mediump' ) { - if ( gl.getShaderPrecisionFormat( 35633, 36337 ).precision > 0 && - gl.getShaderPrecisionFormat( 35632, 36337 ).precision > 0 ) { + if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 && + gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) { return 'mediump'; @@ -14350,8 +15266,7 @@ } - const isWebGL2 = ( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext ) || - ( typeof WebGL2ComputeRenderingContext !== 'undefined' && gl instanceof WebGL2ComputeRenderingContext ); + const isWebGL2 = typeof WebGL2RenderingContext !== 'undefined' && gl.constructor.name === 'WebGL2RenderingContext'; let precision = parameters.precision !== undefined ? parameters.precision : 'highp'; const maxPrecision = getMaxPrecision( precision ); @@ -14367,21 +15282,21 @@ const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true; - const maxTextures = gl.getParameter( 34930 ); - const maxVertexTextures = gl.getParameter( 35660 ); - const maxTextureSize = gl.getParameter( 3379 ); - const maxCubemapSize = gl.getParameter( 34076 ); + const maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS ); + const maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); + const maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE ); + const maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ); - const maxAttributes = gl.getParameter( 34921 ); - const maxVertexUniforms = gl.getParameter( 36347 ); - const maxVaryings = gl.getParameter( 36348 ); - const maxFragmentUniforms = gl.getParameter( 36349 ); + const maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS ); + const maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS ); + const maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS ); + const maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS ); const vertexTextures = maxVertexTextures > 0; const floatFragmentTextures = isWebGL2 || extensions.has( 'OES_texture_float' ); const floatVertexTextures = vertexTextures && floatFragmentTextures; - const maxSamples = isWebGL2 ? gl.getParameter( 36183 ) : 0; + const maxSamples = isWebGL2 ? gl.getParameter( gl.MAX_SAMPLES ) : 0; return { @@ -14433,7 +15348,7 @@ this.numPlanes = 0; this.numIntersection = 0; - this.init = function ( planes, enableLocalClipping, camera ) { + this.init = function ( planes, enableLocalClipping ) { const enabled = planes.length !== 0 || @@ -14445,7 +15360,6 @@ localClippingEnabled = enableLocalClipping; - globalState = projectPlanes( planes, camera, 0 ); numGlobalPlanes = planes.length; return enabled; @@ -14462,7 +15376,12 @@ this.endShadows = function () { renderingShadows = false; - resetGlobalState(); + + }; + + this.setGlobalState = function ( planes, camera ) { + + globalState = projectPlanes( planes, camera, 0 ); }; @@ -14599,7 +15518,7 @@ function get( texture ) { - if ( texture && texture.isTexture && texture.isRenderTargetTexture === false ) { + if ( texture && texture.isTexture ) { const mapping = texture.mapping; @@ -14779,7 +15698,7 @@ } - this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far ); + this.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem ); this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); @@ -14820,6 +15739,8 @@ const _flatCamera = /*@__PURE__*/ new OrthographicCamera(); const _clearColor = /*@__PURE__*/ new Color(); let _oldTarget = null; + let _oldActiveCubeFace = 0; + let _oldActiveMipmapLevel = 0; // Golden Ratio const PHI = ( 1 + Math.sqrt( 5 ) ) / 2; @@ -14885,6 +15806,8 @@ fromScene( scene, sigma = 0, near = 0.1, far = 100 ) { _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); this._setSize( 256 ); @@ -14997,7 +15920,7 @@ _cleanup( outputTarget ) { - this._renderer.setRenderTarget( _oldTarget ); + this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel ); outputTarget.scissorTest = false; _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height ); @@ -15016,6 +15939,8 @@ } _oldTarget = this._renderer.getRenderTarget(); + _oldActiveCubeFace = this._renderer.getActiveCubeFace(); + _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel(); const cubeUVRenderTarget = renderTarget || this._allocateTargets(); this._textureToCubeUV( texture, cubeUVRenderTarget ); @@ -15037,13 +15962,13 @@ generateMipmaps: false, type: HalfFloatType, format: RGBAFormat, - encoding: LinearEncoding, + colorSpace: LinearSRGBColorSpace, depthBuffer: false }; const cubeUVRenderTarget = _createRenderTarget( width, height, params ); - if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width ) { + if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) { if ( this._pingPongRenderTarget !== null ) { @@ -15861,6 +16786,7 @@ if ( capabilities.isWebGL2 ) { getExtension( 'EXT_color_buffer_float' ); + getExtension( 'WEBGL_clip_cull_distance' ); } else { @@ -15908,15 +16834,27 @@ const geometry = event.target; - if ( geometry.index !== null ) { + if ( geometry.index !== null ) { + + attributes.remove( geometry.index ); + + } + + for ( const name in geometry.attributes ) { + + attributes.remove( geometry.attributes[ name ] ); + + } + + for ( const name in geometry.morphAttributes ) { - attributes.remove( geometry.index ); + const array = geometry.morphAttributes[ name ]; - } + for ( let i = 0, l = array.length; i < l; i ++ ) { - for ( const name in geometry.attributes ) { + attributes.remove( array[ i ] ); - attributes.remove( geometry.attributes[ name ] ); + } } @@ -15969,7 +16907,7 @@ for ( const name in geometryAttributes ) { - attributes.update( geometryAttributes[ name ], 34962 ); + attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER ); } @@ -15983,7 +16921,7 @@ for ( let i = 0, l = array.length; i < l; i ++ ) { - attributes.update( array[ i ], 34962 ); + attributes.update( array[ i ], gl.ARRAY_BUFFER ); } @@ -16014,7 +16952,7 @@ } - } else { + } else if ( geometryPosition !== undefined ) { const array = geometryPosition.array; version = geometryPosition.version; @@ -16029,6 +16967,10 @@ } + } else { + + return; + } const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ); @@ -16149,12 +17091,43 @@ } + function renderMultiDraw( starts, counts, drawCount ) { + + if ( drawCount === 0 ) return; + + const extension = extensions.get( 'WEBGL_multi_draw' ); + if ( extension === null ) { + + for ( let i = 0; i < drawCount; i ++ ) { + + this.render( starts[ i ] / bytesPerElement, counts[ i ] ); + + } + + } else { + + extension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount ); + + let elementCount = 0; + for ( let i = 0; i < drawCount; i ++ ) { + + elementCount += counts[ i ]; + + } + + info.update( elementCount, mode, 1 ); + + } + + } + // this.setMode = setMode; this.setIndex = setIndex; this.render = render; this.renderInstances = renderInstances; + this.renderMultiDraw = renderMultiDraw; } @@ -16179,23 +17152,23 @@ switch ( mode ) { - case 4: + case gl.TRIANGLES: render.triangles += instanceCount * ( count / 3 ); break; - case 1: + case gl.LINES: render.lines += instanceCount * ( count / 2 ); break; - case 3: + case gl.LINE_STRIP: render.lines += instanceCount * ( count - 1 ); break; - case 2: + case gl.LINE_LOOP: render.lines += instanceCount * count; break; - case 0: + case gl.POINTS: render.points += instanceCount * count; break; @@ -16209,7 +17182,6 @@ function reset() { - render.frame ++; render.calls = 0; render.triangles = 0; render.points = 0; @@ -16255,7 +17227,7 @@ } - function update( object, geometry, material, program ) { + function update( object, geometry, program ) { const objectInfluences = object.morphTargetInfluences; @@ -16550,11 +17522,31 @@ } - attributes.update( object.instanceMatrix, 34962 ); + if ( updateMap.get( object ) !== frame ) { + + attributes.update( object.instanceMatrix, gl.ARRAY_BUFFER ); + + if ( object.instanceColor !== null ) { + + attributes.update( object.instanceColor, gl.ARRAY_BUFFER ); + + } + + updateMap.set( object, frame ); + + } + + } + + if ( object.isSkinnedMesh ) { + + const skeleton = object.skeleton; + + if ( updateMap.get( skeleton ) !== frame ) { - if ( object.instanceColor !== null ) { + skeleton.update(); - attributes.update( object.instanceColor, 34962 ); + updateMap.set( skeleton, frame ); } @@ -16591,6 +17583,60 @@ } + class DepthTexture extends Texture { + + constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { + + format = format !== undefined ? format : DepthFormat; + + if ( format !== DepthFormat && format !== DepthStencilFormat ) { + + throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); + + } + + if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; + if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; + + super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); + + this.isDepthTexture = true; + + this.image = { width: width, height: height }; + + this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; + this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; + + this.flipY = false; + this.generateMipmaps = false; + + this.compareFunction = null; + + } + + + copy( source ) { + + super.copy( source ); + + this.compareFunction = source.compareFunction; + + return this; + + } + + toJSON( meta ) { + + const data = super.toJSON( meta ); + + if ( this.compareFunction !== null ) data.compareFunction = this.compareFunction; + + return data; + + } + + } + /** * Uniforms of a program. * Those form a tree structure with a special top-level container for the root, @@ -16634,7 +17680,12 @@ * */ + const emptyTexture = /*@__PURE__*/ new Texture(); + + const emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 ); + emptyShadowTexture.compareFunction = LessEqualCompare; + const emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture(); const empty3dTexture = /*@__PURE__*/ new Data3DTexture(); const emptyCubeTexture = /*@__PURE__*/ new CubeTexture(); @@ -17151,7 +18202,9 @@ } - textures.setTexture2D( v || emptyTexture, unit ); + const emptyTexture2D = ( this.type === gl.SAMPLER_2D_SHADOW ) ? emptyShadowTexture : emptyTexture; + + textures.setTexture2D( v || emptyTexture2D, unit ); } @@ -17535,6 +18588,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.setValue = getSingularSetter( activeInfo.type ); // this.path = activeInfo.name; // DEBUG @@ -17550,6 +18604,7 @@ this.id = id; this.addr = addr; this.cache = []; + this.type = activeInfo.type; this.size = activeInfo.size; this.setValue = getPureArraySetter( activeInfo.type ); @@ -17667,7 +18722,7 @@ this.seq = []; this.map = {}; - const n = gl.getProgramParameter( program, 35718 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS ); for ( let i = 0; i < n; ++ i ) { @@ -17742,6 +18797,9 @@ } + // From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/ + const COMPLETION_STATUS_KHR = 0x91B1; + let programIdCount = 0; function handleSource( string, errorLine ) { @@ -17763,17 +18821,40 @@ } - function getEncodingComponents( encoding ) { + function getEncodingComponents( colorSpace ) { + + const workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace ); + const encodingPrimaries = ColorManagement.getPrimaries( colorSpace ); + + let gamutMapping; + + if ( workingPrimaries === encodingPrimaries ) { + + gamutMapping = ''; + + } else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) { + + gamutMapping = 'LinearDisplayP3ToLinearSRGB'; + + } else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) { + + gamutMapping = 'LinearSRGBToLinearDisplayP3'; + + } + + switch ( colorSpace ) { + + case LinearSRGBColorSpace: + case LinearDisplayP3ColorSpace: + return [ gamutMapping, 'LinearTransferOETF' ]; - switch ( encoding ) { + case SRGBColorSpace: + case DisplayP3ColorSpace: + return [ gamutMapping, 'sRGBTransferOETF' ]; - case LinearEncoding: - return [ 'Linear', '( value )' ]; - case sRGBEncoding: - return [ 'sRGB', '( value )' ]; default: - console.warn( 'THREE.WebGLProgram: Unsupported encoding:', encoding ); - return [ 'Linear', '( value )' ]; + console.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace ); + return [ gamutMapping, 'LinearTransferOETF' ]; } @@ -17781,7 +18862,7 @@ function getShaderErrors( gl, shader, type ) { - const status = gl.getShaderParameter( shader, 35713 ); + const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS ); const errors = gl.getShaderInfoLog( shader ).trim(); if ( status && errors === '' ) return ''; @@ -17803,10 +18884,10 @@ } - function getTexelEncodingFunction( functionName, encoding ) { + function getTexelEncodingFunction( functionName, colorSpace ) { - const components = getEncodingComponents( encoding ); - return 'vec4 ' + functionName + '( vec4 value ) { return LinearTo' + components[ 0 ] + components[ 1 ] + '; }'; + const components = getEncodingComponents( colorSpace ); + return `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`; } @@ -17832,6 +18913,10 @@ toneMappingName = 'ACESFilmic'; break; + case AgXToneMapping: + toneMappingName = 'AgX'; + break; + case CustomToneMapping: toneMappingName = 'Custom'; break; @@ -17849,7 +18934,7 @@ function generateExtensions( parameters ) { const chunks = [ - ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.tangentSpaceNormalMap || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', + ( parameters.extensionDerivatives || !! parameters.envMapCubeUVHeight || parameters.bumpMap || parameters.normalMapTangentSpace || parameters.clearcoatNormalMap || parameters.flatShading || parameters.shaderID === 'physical' ) ? '#extension GL_OES_standard_derivatives : enable' : '', ( parameters.extensionFragDepth || parameters.logarithmicDepthBuffer ) && parameters.rendererExtensionFragDepth ? '#extension GL_EXT_frag_depth : enable' : '', ( parameters.extensionDrawBuffers && parameters.rendererExtensionDrawBuffers ) ? '#extension GL_EXT_draw_buffers : require' : '', ( parameters.extensionShaderTextureLOD || parameters.envMap || parameters.transmission ) && parameters.rendererExtensionShaderTextureLod ? '#extension GL_EXT_shader_texture_lod : enable' : '' @@ -17859,6 +18944,16 @@ } + function generateVertexExtensions( parameters ) { + + const chunks = [ + parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '' + ]; + + return chunks.filter( filterEmptyLine ).join( '\n' ); + + } + function generateDefines( defines ) { const chunks = []; @@ -17881,7 +18976,7 @@ const attributes = {}; - const n = gl.getProgramParameter( program, 35721 ); + const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES ); for ( let i = 0; i < n; i ++ ) { @@ -17889,9 +18984,9 @@ const name = info.name; let locationSize = 1; - if ( info.type === 35674 ) locationSize = 2; - if ( info.type === 35675 ) locationSize = 3; - if ( info.type === 35676 ) locationSize = 4; + if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2; + if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3; + if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4; // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); @@ -17950,13 +19045,30 @@ } + const shaderChunkMap = new Map( [ + [ 'encodings_fragment', 'colorspace_fragment' ], // @deprecated, r154 + [ 'encodings_pars_fragment', 'colorspace_pars_fragment' ], // @deprecated, r154 + [ 'output_fragment', 'opaque_fragment' ], // @deprecated, r154 + ] ); + function includeReplacer( match, include ) { - const string = ShaderChunk[ include ]; + let string = ShaderChunk[ include ]; if ( string === undefined ) { - throw new Error( 'Can not resolve #include <' + include + '>' ); + const newInclude = shaderChunkMap.get( include ); + + if ( newInclude !== undefined ) { + + string = ShaderChunk[ newInclude ]; + console.warn( 'THREE.WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.', include, newInclude ); + + } else { + + throw new Error( 'Can not resolve #include <' + include + '>' ); + + } } @@ -18146,6 +19258,8 @@ const customExtensions = parameters.isWebGL2 ? '' : generateExtensions( parameters ); + const customVertexExtensions = generateVertexExtensions( parameters ); + const customDefines = generateDefines( defines ); const program = gl.createProgram(); @@ -18157,6 +19271,9 @@ prefixVertex = [ + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18170,6 +19287,10 @@ prefixFragment = [ customExtensions, + + '#define SHADER_TYPE ' + parameters.shaderType, + '#define SHADER_NAME ' + parameters.shaderName, + customDefines ].filter( filterEmptyLine ).join( '\n' ); @@ -18186,28 +19307,33 @@ 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.instancing ? '#define USE_INSTANCING' : '', parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '', - parameters.supportsVertexTextures ? '#define VERTEX_TEXTURES' : '', - - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.envMap ? '#define USE_ENVMAP' : '', parameters.envMap ? '#define ' + envMapModeDefine : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '', @@ -18216,28 +19342,65 @@ parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '', parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', - parameters.displacementMap && parameters.supportsVertexTextures ? '#define USE_DISPLACEMENTMAP' : '', - parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', + + // + + parameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '', + parameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '', + parameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '', + parameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '', + parameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '', + parameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '', + parameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '', + parameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '', + + parameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '', + parameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '', + + parameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '', + + parameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '', + parameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '', + parameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '', + + parameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '', + parameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '', + + parameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '', + parameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '', + + parameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '', + parameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '', + parameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '', - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '', + parameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '', + + // + + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.flatShading ? '#define FLAT_SHADED' : '', @@ -18257,6 +19420,10 @@ parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18284,6 +19451,24 @@ 'attribute vec3 normal;', 'attribute vec2 uv;', + '#ifdef USE_UV1', + + ' attribute vec2 uv1;', + + '#endif', + + '#ifdef USE_UV2', + + ' attribute vec2 uv2;', + + '#endif', + + '#ifdef USE_UV3', + + ' attribute vec2 uv3;', + + '#endif', + '#ifdef USE_TANGENT', ' attribute vec4 tangent;', @@ -18342,12 +19527,13 @@ generatePrecision( parameters ), + '#define SHADER_TYPE ' + parameters.shaderType, '#define SHADER_NAME ' + parameters.shaderName, customDefines, - ( parameters.useFog && parameters.fog ) ? '#define USE_FOG' : '', - ( parameters.useFog && parameters.fogExp2 ) ? '#define FOG_EXP2' : '', + parameters.useFog && parameters.fog ? '#define USE_FOG' : '', + parameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '', parameters.map ? '#define USE_MAP' : '', parameters.matcap ? '#define USE_MATCAP' : '', @@ -18360,11 +19546,14 @@ envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '', parameters.lightMap ? '#define USE_LIGHTMAP' : '', parameters.aoMap ? '#define USE_AOMAP' : '', - parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', parameters.bumpMap ? '#define USE_BUMPMAP' : '', parameters.normalMap ? '#define USE_NORMALMAP' : '', - ( parameters.normalMap && parameters.objectSpaceNormalMap ) ? '#define OBJECTSPACE_NORMALMAP' : '', - ( parameters.normalMap && parameters.tangentSpaceNormalMap ) ? '#define TANGENTSPACE_NORMALMAP' : '', + parameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '', + parameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '', + parameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '', + + parameters.anisotropy ? '#define USE_ANISOTROPY' : '', + parameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '', parameters.clearcoat ? '#define USE_CLEARCOAT' : '', parameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '', @@ -18376,29 +19565,32 @@ parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '', parameters.specularMap ? '#define USE_SPECULARMAP' : '', - parameters.specularIntensityMap ? '#define USE_SPECULARINTENSITYMAP' : '', - parameters.specularColorMap ? '#define USE_SPECULARCOLORMAP' : '', + parameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '', + parameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '', + parameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '', parameters.metalnessMap ? '#define USE_METALNESSMAP' : '', parameters.alphaMap ? '#define USE_ALPHAMAP' : '', parameters.alphaTest ? '#define USE_ALPHATEST' : '', + parameters.alphaHash ? '#define USE_ALPHAHASH' : '', parameters.sheen ? '#define USE_SHEEN' : '', - parameters.sheenColorMap ? '#define USE_SHEENCOLORMAP' : '', - parameters.sheenRoughnessMap ? '#define USE_SHEENROUGHNESSMAP' : '', + parameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '', + parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '', parameters.transmission ? '#define USE_TRANSMISSION' : '', parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '', parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '', - parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', - - parameters.vertexTangents ? '#define USE_TANGENT' : '', + parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '', parameters.vertexColors || parameters.instancingColor ? '#define USE_COLOR' : '', parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '', - parameters.vertexUvs ? '#define USE_UV' : '', - parameters.uvsVertexOnly ? '#define UVS_VERTEX_ONLY' : '', + parameters.vertexUv1s ? '#define USE_UV1' : '', + parameters.vertexUv2s ? '#define USE_UV2' : '', + parameters.vertexUv3s ? '#define USE_UV3' : '', + + parameters.pointsUvs ? '#define USE_POINTS_UV' : '', parameters.gradientMap ? '#define USE_GRADIENTMAP' : '', @@ -18412,7 +19604,11 @@ parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '', - parameters.physicallyCorrectLights ? '#define PHYSICALLY_CORRECT_LIGHTS' : '', + parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '', + + parameters.useLegacyLights ? '#define LEGACY_LIGHTS' : '', + + parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '', parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '', ( parameters.logarithmicDepthBuffer && parameters.rendererExtensionFragDepth ) ? '#define USE_LOGDEPTHBUF_EXT' : '', @@ -18428,8 +19624,8 @@ parameters.dithering ? '#define DITHERING' : '', parameters.opaque ? '#define OPAQUE' : '', - ShaderChunk[ 'encodings_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below - getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputEncoding ), + ShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below + getTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ), parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '', @@ -18457,6 +19653,7 @@ versionString = '#version 300 es\n'; prefixVertex = [ + customVertexExtensions, 'precision mediump sampler2DArray;', '#define attribute in', '#define varying out', @@ -18464,6 +19661,7 @@ ].join( '\n' ) + '\n' + prefixVertex; prefixFragment = [ + 'precision mediump sampler2DArray;', '#define varying in', ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', @@ -18487,8 +19685,8 @@ // console.log( '*VERTEX*', vertexGlsl ); // console.log( '*FRAGMENT*', fragmentGlsl ); - const glVertexShader = WebGLShader( gl, 35633, vertexGlsl ); - const glFragmentShader = WebGLShader( gl, 35632, fragmentGlsl ); + const glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl ); + const glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl ); gl.attachShader( program, glVertexShader ); gl.attachShader( program, glFragmentShader ); @@ -18508,77 +19706,94 @@ gl.linkProgram( program ); - // check for link errors - if ( renderer.debug.checkShaderErrors ) { + function onFirstUse( self ) { - const programLog = gl.getProgramInfoLog( program ).trim(); - const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); - const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); + // check for link errors + if ( renderer.debug.checkShaderErrors ) { - let runnable = true; - let haveDiagnostics = true; + const programLog = gl.getProgramInfoLog( program ).trim(); + const vertexLog = gl.getShaderInfoLog( glVertexShader ).trim(); + const fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim(); - if ( gl.getProgramParameter( program, 35714 ) === false ) { + let runnable = true; + let haveDiagnostics = true; - runnable = false; + if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) { - const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); - const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); + runnable = false; - console.error( - 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + - 'VALIDATE_STATUS ' + gl.getProgramParameter( program, 35715 ) + '\n\n' + - 'Program Info Log: ' + programLog + '\n' + - vertexErrors + '\n' + - fragmentErrors - ); + if ( typeof renderer.debug.onShaderError === 'function' ) { + + renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader ); - } else if ( programLog !== '' ) { + } else { - console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); + // default error reporting - } else if ( vertexLog === '' || fragmentLog === '' ) { + const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' ); + const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' ); - haveDiagnostics = false; + console.error( + 'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' + + 'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' + + 'Program Info Log: ' + programLog + '\n' + + vertexErrors + '\n' + + fragmentErrors + ); - } + } - if ( haveDiagnostics ) { + } else if ( programLog !== '' ) { - this.diagnostics = { + console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog ); - runnable: runnable, + } else if ( vertexLog === '' || fragmentLog === '' ) { - programLog: programLog, + haveDiagnostics = false; - vertexShader: { + } - log: vertexLog, - prefix: prefixVertex + if ( haveDiagnostics ) { - }, + self.diagnostics = { - fragmentShader: { + runnable: runnable, - log: fragmentLog, - prefix: prefixFragment + programLog: programLog, - } + vertexShader: { - }; + log: vertexLog, + prefix: prefixVertex + + }, + + fragmentShader: { + + log: fragmentLog, + prefix: prefixFragment + + } + + }; + + } } - } + // Clean up + + // Crashes in iOS9 and iOS10. #18402 + // gl.detachShader( program, glVertexShader ); + // gl.detachShader( program, glFragmentShader ); - // Clean up + gl.deleteShader( glVertexShader ); + gl.deleteShader( glFragmentShader ); - // Crashes in iOS9 and iOS10. #18402 - // gl.detachShader( program, glVertexShader ); - // gl.detachShader( program, glFragmentShader ); + cachedUniforms = new WebGLUniforms( gl, program ); + cachedAttributes = fetchAttributeLocations( gl, program ); - gl.deleteShader( glVertexShader ); - gl.deleteShader( glFragmentShader ); + } // set up caching for uniform locations @@ -18588,7 +19803,8 @@ if ( cachedUniforms === undefined ) { - cachedUniforms = new WebGLUniforms( gl, program ); + // Populates cachedUniforms and cachedAttributes + onFirstUse( this ); } @@ -18604,7 +19820,8 @@ if ( cachedAttributes === undefined ) { - cachedAttributes = fetchAttributeLocations( gl, program ); + // Populates cachedAttributes and cachedUniforms + onFirstUse( this ); } @@ -18612,6 +19829,23 @@ }; + // indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, + // flag the program as ready immediately. It may cause a stall when it's first used. + + let programReady = ( parameters.rendererExtensionParallelShaderCompile === false ); + + this.isReady = function () { + + if ( programReady === false ) { + + programReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR ); + + } + + return programReady; + + }; + // free resource this.destroy = function () { @@ -18625,6 +19859,7 @@ // + this.type = parameters.shaderType; this.name = parameters.shaderName; this.id = programIdCount ++; this.cacheKey = cacheKey; @@ -18637,7 +19872,7 @@ } - let _id = 0; + let _id$1 = 0; class WebGLShaderCache { @@ -18751,7 +19986,7 @@ constructor( code ) { - this.id = _id ++; + this.id = _id$1 ++; this.code = code; this.usedTimes = 0; @@ -18766,9 +20001,10 @@ const _customShaders = new WebGLShaderCache(); const programs = []; - const isWebGL2 = capabilities.isWebGL2; + const IS_WEBGL2 = capabilities.isWebGL2; const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer; - const vertexTextures = capabilities.vertexTextures; + const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures; + let precision = capabilities.precision; const shaderIDs = { @@ -18789,6 +20025,14 @@ SpriteMaterial: 'sprite' }; + function getChannel( value ) { + + if ( value === 0 ) return 'uv'; + + return `uv${ value }`; + + } + function getParameters( material, lights, shadows, scene, object ) { const fog = scene.fog; @@ -18828,40 +20072,104 @@ // - let vertexShader, fragmentShader; - let customVertexShaderID, customFragmentShaderID; + let vertexShader, fragmentShader; + let customVertexShaderID, customFragmentShaderID; + + if ( shaderID ) { + + const shader = ShaderLib[ shaderID ]; + + vertexShader = shader.vertexShader; + fragmentShader = shader.fragmentShader; + + } else { + + vertexShader = material.vertexShader; + fragmentShader = material.fragmentShader; + + _customShaders.update( material ); + + customVertexShaderID = _customShaders.getVertexShaderID( material ); + customFragmentShaderID = _customShaders.getFragmentShaderID( material ); + + } + + const currentRenderTarget = renderer.getRenderTarget(); + + const IS_INSTANCEDMESH = object.isInstancedMesh === true; + const IS_BATCHEDMESH = object.isBatchedMesh === true; + + const HAS_MAP = !! material.map; + const HAS_MATCAP = !! material.matcap; + const HAS_ENVMAP = !! envMap; + const HAS_AOMAP = !! material.aoMap; + const HAS_LIGHTMAP = !! material.lightMap; + const HAS_BUMPMAP = !! material.bumpMap; + const HAS_NORMALMAP = !! material.normalMap; + const HAS_DISPLACEMENTMAP = !! material.displacementMap; + const HAS_EMISSIVEMAP = !! material.emissiveMap; + + const HAS_METALNESSMAP = !! material.metalnessMap; + const HAS_ROUGHNESSMAP = !! material.roughnessMap; + + const HAS_ANISOTROPY = material.anisotropy > 0; + const HAS_CLEARCOAT = material.clearcoat > 0; + const HAS_IRIDESCENCE = material.iridescence > 0; + const HAS_SHEEN = material.sheen > 0; + const HAS_TRANSMISSION = material.transmission > 0; + + const HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap; + + const HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap; + const HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap; + const HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap; + + const HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap; + const HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap; + + const HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap; + const HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap; + + const HAS_SPECULARMAP = !! material.specularMap; + const HAS_SPECULAR_COLORMAP = !! material.specularColorMap; + const HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap; + + const HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap; + const HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap; + + const HAS_GRADIENTMAP = !! material.gradientMap; + + const HAS_ALPHAMAP = !! material.alphaMap; - if ( shaderID ) { + const HAS_ALPHATEST = material.alphaTest > 0; - const shader = ShaderLib[ shaderID ]; + const HAS_ALPHAHASH = !! material.alphaHash; - vertexShader = shader.vertexShader; - fragmentShader = shader.fragmentShader; + const HAS_EXTENSIONS = !! material.extensions; - } else { + const HAS_ATTRIBUTE_UV1 = !! geometry.attributes.uv1; + const HAS_ATTRIBUTE_UV2 = !! geometry.attributes.uv2; + const HAS_ATTRIBUTE_UV3 = !! geometry.attributes.uv3; - vertexShader = material.vertexShader; - fragmentShader = material.fragmentShader; + let toneMapping = NoToneMapping; - _customShaders.update( material ); + if ( material.toneMapped ) { - customVertexShaderID = _customShaders.getVertexShaderID( material ); - customFragmentShaderID = _customShaders.getFragmentShaderID( material ); + if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) { - } + toneMapping = renderer.toneMapping; - const currentRenderTarget = renderer.getRenderTarget(); + } - const useAlphaTest = material.alphaTest > 0; - const useClearcoat = material.clearcoat > 0; - const useIridescence = material.iridescence > 0; + } const parameters = { - isWebGL2: isWebGL2, + isWebGL2: IS_WEBGL2, shaderID: shaderID, - shaderName: material.type, + shaderType: material.type, + shaderName: material.name, vertexShader: vertexShader, fragmentShader: fragmentShader, @@ -18875,72 +20183,117 @@ precision: precision, - instancing: object.isInstancedMesh === true, - instancingColor: object.isInstancedMesh === true && object.instanceColor !== null, + batching: IS_BATCHEDMESH, + instancing: IS_INSTANCEDMESH, + instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null, - supportsVertexTextures: vertexTextures, - outputEncoding: ( currentRenderTarget === null ) ? renderer.outputEncoding : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.encoding : LinearEncoding ), - map: !! material.map, - matcap: !! material.matcap, - envMap: !! envMap, - envMapMode: envMap && envMap.mapping, + supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES, + outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ), + + map: HAS_MAP, + matcap: HAS_MATCAP, + envMap: HAS_ENVMAP, + envMapMode: HAS_ENVMAP && envMap.mapping, envMapCubeUVHeight: envMapCubeUVHeight, - lightMap: !! material.lightMap, - aoMap: !! material.aoMap, - emissiveMap: !! material.emissiveMap, - bumpMap: !! material.bumpMap, - normalMap: !! material.normalMap, - objectSpaceNormalMap: material.normalMapType === ObjectSpaceNormalMap, - tangentSpaceNormalMap: material.normalMapType === TangentSpaceNormalMap, - - decodeVideoTexture: !! material.map && ( material.map.isVideoTexture === true ) && ( material.map.encoding === sRGBEncoding ), - - clearcoat: useClearcoat, - clearcoatMap: useClearcoat && !! material.clearcoatMap, - clearcoatRoughnessMap: useClearcoat && !! material.clearcoatRoughnessMap, - clearcoatNormalMap: useClearcoat && !! material.clearcoatNormalMap, - - iridescence: useIridescence, - iridescenceMap: useIridescence && !! material.iridescenceMap, - iridescenceThicknessMap: useIridescence && !! material.iridescenceThicknessMap, - - displacementMap: !! material.displacementMap, - roughnessMap: !! material.roughnessMap, - metalnessMap: !! material.metalnessMap, - specularMap: !! material.specularMap, - specularIntensityMap: !! material.specularIntensityMap, - specularColorMap: !! material.specularColorMap, + aoMap: HAS_AOMAP, + lightMap: HAS_LIGHTMAP, + bumpMap: HAS_BUMPMAP, + normalMap: HAS_NORMALMAP, + displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP, + emissiveMap: HAS_EMISSIVEMAP, - opaque: material.transparent === false && material.blending === NormalBlending, + normalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap, + normalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap, + + 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, + + 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, - alphaMap: !! material.alphaMap, - alphaTest: useAlphaTest, + transmission: HAS_TRANSMISSION, + transmissionMap: HAS_TRANSMISSIONMAP, + thicknessMap: HAS_THICKNESSMAP, - gradientMap: !! material.gradientMap, + gradientMap: HAS_GRADIENTMAP, - sheen: material.sheen > 0, - sheenColorMap: !! material.sheenColorMap, - sheenRoughnessMap: !! material.sheenRoughnessMap, + opaque: material.transparent === false && material.blending === NormalBlending, - transmission: material.transmission > 0, - transmissionMap: !! material.transmissionMap, - thicknessMap: !! material.thicknessMap, + alphaMap: HAS_ALPHAMAP, + alphaTest: HAS_ALPHATEST, + alphaHash: HAS_ALPHAHASH, combine: material.combine, - vertexTangents: ( !! material.normalMap && !! geometry.attributes.tangent ), + // + + mapUv: HAS_MAP && getChannel( material.map.channel ), + aoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ), + lightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ), + bumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ), + normalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ), + displacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ), + emissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ), + + metalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ), + roughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ), + + anisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ), + + clearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ), + clearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ), + clearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ), + + iridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ), + iridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ), + + sheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ), + sheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ), + + specularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ), + specularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ), + specularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ), + + transmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ), + thicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ), + + alphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ), + + // + + vertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ), vertexColors: material.vertexColors, vertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4, - vertexUvs: !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatMap || !! material.clearcoatRoughnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || !! material.displacementMap || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || !! material.sheenColorMap || !! material.sheenRoughnessMap, - uvsVertexOnly: ! ( !! material.map || !! material.bumpMap || !! material.normalMap || !! material.specularMap || !! material.alphaMap || !! material.emissiveMap || !! material.roughnessMap || !! material.metalnessMap || !! material.clearcoatNormalMap || !! material.iridescenceMap || !! material.iridescenceThicknessMap || material.transmission > 0 || !! material.transmissionMap || !! material.thicknessMap || !! material.specularIntensityMap || !! material.specularColorMap || material.sheen > 0 || !! material.sheenColorMap || !! material.sheenRoughnessMap ) && !! material.displacementMap, + vertexUv1s: HAS_ATTRIBUTE_UV1, + vertexUv2s: HAS_ATTRIBUTE_UV2, + vertexUv3s: HAS_ATTRIBUTE_UV3, + + pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ), fog: !! fog, useFog: material.fog === true, fogExp2: ( fog && fog.isFogExp2 ), - flatShading: !! material.flatShading, + flatShading: material.flatShading === true, - sizeAttenuation: material.sizeAttenuation, + sizeAttenuation: material.sizeAttenuation === true, logarithmicDepthBuffer: logarithmicDepthBuffer, skinning: object.isSkinnedMesh === true, @@ -18963,6 +20316,8 @@ numSpotLightShadows: lights.spotShadowMap.length, numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps, + numLightProbes: lights.numLightProbes, + numClippingPlanes: clipping.numPlanes, numClipIntersection: clipping.numIntersection, @@ -18971,27 +20326,31 @@ shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0, shadowMapType: renderer.shadowMap.type, - toneMapping: material.toneMapped ? renderer.toneMapping : NoToneMapping, - physicallyCorrectLights: renderer.physicallyCorrectLights, + toneMapping: toneMapping, + useLegacyLights: renderer._useLegacyLights, + + decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ), premultipliedAlpha: material.premultipliedAlpha, doubleSided: material.side === DoubleSide, flipSided: material.side === BackSide, - useDepthPacking: !! material.depthPacking, + useDepthPacking: material.depthPacking >= 0, depthPacking: material.depthPacking || 0, index0AttributeName: material.index0AttributeName, - extensionDerivatives: material.extensions && material.extensions.derivatives, - extensionFragDepth: material.extensions && material.extensions.fragDepth, - extensionDrawBuffers: material.extensions && material.extensions.drawBuffers, - extensionShaderTextureLOD: material.extensions && material.extensions.shaderTextureLOD, + extensionDerivatives: HAS_EXTENSIONS && material.extensions.derivatives === true, + extensionFragDepth: HAS_EXTENSIONS && material.extensions.fragDepth === true, + extensionDrawBuffers: HAS_EXTENSIONS && material.extensions.drawBuffers === true, + extensionShaderTextureLOD: HAS_EXTENSIONS && material.extensions.shaderTextureLOD === true, + extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance && extensions.has( 'WEBGL_clip_cull_distance' ), - rendererExtensionFragDepth: isWebGL2 || extensions.has( 'EXT_frag_depth' ), - rendererExtensionDrawBuffers: isWebGL2 || extensions.has( 'WEBGL_draw_buffers' ), - rendererExtensionShaderTextureLod: isWebGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionFragDepth: IS_WEBGL2 || extensions.has( 'EXT_frag_depth' ), + rendererExtensionDrawBuffers: IS_WEBGL2 || extensions.has( 'WEBGL_draw_buffers' ), + rendererExtensionShaderTextureLod: IS_WEBGL2 || extensions.has( 'EXT_shader_texture_lod' ), + rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ), customProgramCacheKey: material.customProgramCacheKey() @@ -19031,7 +20390,7 @@ getProgramCacheKeyParameters( array, parameters ); getProgramCacheKeyBooleans( array, parameters ); - array.push( renderer.outputEncoding ); + array.push( renderer.outputColorSpace ); } @@ -19044,11 +20403,33 @@ function getProgramCacheKeyParameters( array, parameters ) { array.push( parameters.precision ); - array.push( parameters.outputEncoding ); + 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.vertexUvs ); array.push( parameters.fogExp2 ); array.push( parameters.sizeAttenuation ); array.push( parameters.morphTargetsCount ); @@ -19063,6 +20444,7 @@ 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 ); @@ -19083,64 +20465,38 @@ _programLayers.enable( 2 ); if ( parameters.instancingColor ) _programLayers.enable( 3 ); - if ( parameters.map ) - _programLayers.enable( 4 ); if ( parameters.matcap ) - _programLayers.enable( 5 ); + _programLayers.enable( 4 ); if ( parameters.envMap ) + _programLayers.enable( 5 ); + if ( parameters.normalMapObjectSpace ) _programLayers.enable( 6 ); - if ( parameters.lightMap ) + if ( parameters.normalMapTangentSpace ) _programLayers.enable( 7 ); - if ( parameters.aoMap ) + if ( parameters.clearcoat ) _programLayers.enable( 8 ); - if ( parameters.emissiveMap ) + if ( parameters.iridescence ) _programLayers.enable( 9 ); - if ( parameters.bumpMap ) + if ( parameters.alphaTest ) _programLayers.enable( 10 ); - if ( parameters.normalMap ) + if ( parameters.vertexColors ) _programLayers.enable( 11 ); - if ( parameters.objectSpaceNormalMap ) + if ( parameters.vertexAlphas ) _programLayers.enable( 12 ); - if ( parameters.tangentSpaceNormalMap ) + if ( parameters.vertexUv1s ) _programLayers.enable( 13 ); - if ( parameters.clearcoat ) + if ( parameters.vertexUv2s ) _programLayers.enable( 14 ); - if ( parameters.clearcoatMap ) + if ( parameters.vertexUv3s ) _programLayers.enable( 15 ); - if ( parameters.clearcoatRoughnessMap ) + if ( parameters.vertexTangents ) _programLayers.enable( 16 ); - if ( parameters.clearcoatNormalMap ) + if ( parameters.anisotropy ) _programLayers.enable( 17 ); - if ( parameters.iridescence ) + if ( parameters.alphaHash ) _programLayers.enable( 18 ); - if ( parameters.iridescenceMap ) + if ( parameters.batching ) _programLayers.enable( 19 ); - if ( parameters.iridescenceThicknessMap ) - _programLayers.enable( 20 ); - if ( parameters.displacementMap ) - _programLayers.enable( 21 ); - if ( parameters.specularMap ) - _programLayers.enable( 22 ); - if ( parameters.roughnessMap ) - _programLayers.enable( 23 ); - if ( parameters.metalnessMap ) - _programLayers.enable( 24 ); - if ( parameters.gradientMap ) - _programLayers.enable( 25 ); - if ( parameters.alphaMap ) - _programLayers.enable( 26 ); - if ( parameters.alphaTest ) - _programLayers.enable( 27 ); - if ( parameters.vertexColors ) - _programLayers.enable( 28 ); - if ( parameters.vertexAlphas ) - _programLayers.enable( 29 ); - if ( parameters.vertexUvs ) - _programLayers.enable( 30 ); - if ( parameters.vertexTangents ) - _programLayers.enable( 31 ); - if ( parameters.uvsVertexOnly ) - _programLayers.enable( 32 ); array.push( _programLayers.mask ); _programLayers.disableAll(); @@ -19165,7 +20521,7 @@ _programLayers.enable( 8 ); if ( parameters.shadowMapEnabled ) _programLayers.enable( 9 ); - if ( parameters.physicallyCorrectLights ) + if ( parameters.useLegacyLights ) _programLayers.enable( 10 ); if ( parameters.doubleSided ) _programLayers.enable( 11 ); @@ -19175,26 +20531,16 @@ _programLayers.enable( 13 ); if ( parameters.dithering ) _programLayers.enable( 14 ); - if ( parameters.specularIntensityMap ) + if ( parameters.transmission ) _programLayers.enable( 15 ); - if ( parameters.specularColorMap ) + if ( parameters.sheen ) _programLayers.enable( 16 ); - if ( parameters.transmission ) + if ( parameters.opaque ) _programLayers.enable( 17 ); - if ( parameters.transmissionMap ) + if ( parameters.pointsUvs ) _programLayers.enable( 18 ); - if ( parameters.thicknessMap ) - _programLayers.enable( 19 ); - if ( parameters.sheen ) - _programLayers.enable( 20 ); - if ( parameters.sheenColorMap ) - _programLayers.enable( 21 ); - if ( parameters.sheenRoughnessMap ) - _programLayers.enable( 22 ); if ( parameters.decodeVideoTexture ) - _programLayers.enable( 23 ); - if ( parameters.opaque ) - _programLayers.enable( 24 ); + _programLayers.enable( 19 ); array.push( _programLayers.mask ); @@ -19741,7 +21087,9 @@ numDirectionalShadows: - 1, numPointShadows: - 1, numSpotShadows: - 1, - numSpotMaps: - 1 + numSpotMaps: - 1, + + numLightProbes: - 1 }, ambient: [ 0, 0, 0 ], @@ -19763,7 +21111,8 @@ pointShadowMap: [], pointShadowMatrix: [], hemi: [], - numSpotLightShadowsWithMaps: 0 + numSpotLightShadowsWithMaps: 0, + numLightProbes: 0 }; @@ -19773,7 +21122,7 @@ const matrix4 = new Matrix4(); const matrix42 = new Matrix4(); - function setup( lights, physicallyCorrectLights ) { + function setup( lights, useLegacyLights ) { let r = 0, g = 0, b = 0; @@ -19791,11 +21140,13 @@ let numSpotMaps = 0; let numSpotShadowsWithMaps = 0; + let numLightProbes = 0; + // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] lights.sort( shadowCastingAndTexturingLightsFirst ); // artist-friendly light intensity scaling factor - const scaleFactor = ( physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( useLegacyLights === true ) ? Math.PI : 1; for ( let i = 0, l = lights.length; i < l; i ++ ) { @@ -19821,6 +21172,8 @@ } + numLightProbes ++; + } else if ( light.isDirectionalLight ) { const uniforms = cache.get( light ); @@ -19967,8 +21320,17 @@ // WebGL 2 - state.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1; - state.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2; + if ( extensions.has( 'OES_texture_float_linear' ) === true ) { + + 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; + + } } else { @@ -20008,7 +21370,8 @@ hash.numDirectionalShadows !== numDirectionalShadows || hash.numPointShadows !== numPointShadows || hash.numSpotShadows !== numSpotShadows || - hash.numSpotMaps !== numSpotMaps ) { + hash.numSpotMaps !== numSpotMaps || + hash.numLightProbes !== numLightProbes ) { state.directional.length = directionalLength; state.spot.length = spotLength; @@ -20027,6 +21390,7 @@ state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps; state.spotLightMap.length = numSpotMaps; state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps; + state.numLightProbes = numLightProbes; hash.directionalLength = directionalLength; hash.pointLength = pointLength; @@ -20039,6 +21403,8 @@ hash.numSpotShadows = numSpotShadows; hash.numSpotMaps = numSpotMaps; + hash.numLightProbes = numLightProbes; + state.version = nextVersion ++; } @@ -20163,9 +21529,9 @@ } - function setupLights( physicallyCorrectLights ) { + function setupLights( useLegacyLights ) { - lights.setup( lightsArray, physicallyCorrectLights ); + lights.setup( lightsArray, useLegacyLights ); } @@ -20300,10 +21666,6 @@ this.type = 'MeshDistanceMaterial'; - this.referencePosition = new Vector3(); - this.nearDistance = 1; - this.farDistance = 1000; - this.map = null; this.alphaMap = null; @@ -20320,10 +21682,6 @@ super.copy( source ); - this.referencePosition.copy( source.referencePosition ); - this.nearDistance = source.nearDistance; - this.farDistance = source.farDistance; - this.map = source.map; this.alphaMap = source.alphaMap; @@ -20358,7 +21716,7 @@ _maxTextureSize = _capabilities.maxTextureSize; - const shadowSide = { 0: BackSide, 1: FrontSide, 2: DoubleSide }; + const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }; const shadowMaterialVertical = new ShaderMaterial( { defines: { @@ -20397,6 +21755,7 @@ this.needsUpdate = false; this.type = PCFShadowMap; + let _previousType = this.type; this.render = function ( lights, scene, camera ) { @@ -20417,6 +21776,11 @@ _state.buffers.depth.setTest( true ); _state.setScissorTest( false ); + // check for shadow map type changes + + const toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap ); + const fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap ); + // render depth map for ( let i = 0, il = lights.length; i < il; i ++ ) { @@ -20461,10 +21825,16 @@ } - if ( shadow.map === null ) { + if ( shadow.map === null || toVSM === true || fromVSM === true ) { const pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {}; + if ( shadow.map !== null ) { + + shadow.map.dispose(); + + } + shadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars ); shadow.map.texture.name = light.name + '.shadowMap'; @@ -20510,6 +21880,8 @@ } + _previousType = this.type; + scope.needsUpdate = false; _renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel ); @@ -20556,7 +21928,7 @@ } - function getDepthMaterial( object, material, light, shadowCameraNear, shadowCameraFar, type ) { + function getDepthMaterial( object, material, light, type ) { let result = null; @@ -20570,37 +21942,38 @@ result = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial; - } + if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || + ( material.displacementMap && material.displacementScale !== 0 ) || + ( material.alphaMap && material.alphaTest > 0 ) || + ( material.map && material.alphaTest > 0 ) ) { - if ( ( _renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) || - ( material.displacementMap && material.displacementScale !== 0 ) || - ( material.alphaMap && material.alphaTest > 0 ) || - ( material.map && material.alphaTest > 0 ) ) { + // in this case we need a unique material instance reflecting the + // appropriate state - // in this case we need a unique material instance reflecting the - // appropriate state + const keyA = result.uuid, keyB = material.uuid; - const keyA = result.uuid, keyB = material.uuid; + let materialsForVariant = _materialCache[ keyA ]; - let materialsForVariant = _materialCache[ keyA ]; + if ( materialsForVariant === undefined ) { - if ( materialsForVariant === undefined ) { + materialsForVariant = {}; + _materialCache[ keyA ] = materialsForVariant; - materialsForVariant = {}; - _materialCache[ keyA ] = materialsForVariant; + } - } + let cachedMaterial = materialsForVariant[ keyB ]; - let cachedMaterial = materialsForVariant[ keyB ]; + if ( cachedMaterial === undefined ) { - if ( cachedMaterial === undefined ) { + cachedMaterial = result.clone(); + materialsForVariant[ keyB ] = cachedMaterial; + material.addEventListener( 'dispose', onMaterialDispose ); - cachedMaterial = result.clone(); - materialsForVariant[ keyB ] = cachedMaterial; + } - } + result = cachedMaterial; - result = cachedMaterial; + } } @@ -20634,9 +22007,8 @@ if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) { - result.referencePosition.setFromMatrixPosition( light.matrixWorld ); - result.nearDistance = shadowCameraNear; - result.farDistance = shadowCameraFar; + const materialProperties = _renderer.properties.get( result ); + materialProperties.light = light; } @@ -20670,20 +22042,28 @@ if ( groupMaterial && groupMaterial.visible ) { - const depthMaterial = getDepthMaterial( object, groupMaterial, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, groupMaterial, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, group ); + } } } else if ( material.visible ) { - const depthMaterial = getDepthMaterial( object, material, light, shadowCamera.near, shadowCamera.far, type ); + const depthMaterial = getDepthMaterial( object, material, light, type ); + + object.onBeforeShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); _renderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null ); + object.onAfterShadow( _renderer, object, camera, shadowCamera, geometry, depthMaterial, null ); + } } @@ -20700,6 +22080,32 @@ } + function onMaterialDispose( event ) { + + const material = event.target; + + material.removeEventListener( 'dispose', onMaterialDispose ); + + // make sure to remove the unique distance/depth materials used for shadow map rendering + + for ( const id in _materialCache ) { + + const cache = _materialCache[ id ]; + + const uuid = event.target.uuid; + + if ( uuid in cache ) { + + const shadowMaterial = cache[ uuid ]; + shadowMaterial.dispose(); + delete cache[ uuid ]; + + } + + } + + } + } function WebGLState( gl, extensions, capabilities ) { @@ -20779,11 +22185,11 @@ if ( depthTest ) { - enable( 2929 ); + enable( gl.DEPTH_TEST ); } else { - disable( 2929 ); + disable( gl.DEPTH_TEST ); } @@ -20808,47 +22214,47 @@ case NeverDepth: - gl.depthFunc( 512 ); + gl.depthFunc( gl.NEVER ); break; case AlwaysDepth: - gl.depthFunc( 519 ); + gl.depthFunc( gl.ALWAYS ); break; case LessDepth: - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); break; case LessEqualDepth: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); break; case EqualDepth: - gl.depthFunc( 514 ); + gl.depthFunc( gl.EQUAL ); break; case GreaterEqualDepth: - gl.depthFunc( 518 ); + gl.depthFunc( gl.GEQUAL ); break; case GreaterDepth: - gl.depthFunc( 516 ); + gl.depthFunc( gl.GREATER ); break; case NotEqualDepth: - gl.depthFunc( 517 ); + gl.depthFunc( gl.NOTEQUAL ); break; default: - gl.depthFunc( 515 ); + gl.depthFunc( gl.LEQUAL ); } @@ -20910,11 +22316,11 @@ if ( stencilTest ) { - enable( 2960 ); + enable( gl.STENCIL_TEST ); } else { - disable( 2960 ); + disable( gl.STENCIL_TEST ); } @@ -21008,7 +22414,7 @@ const stencilBuffer = new StencilBuffer(); const uboBindings = new WeakMap(); - const uboProgamMap = new WeakMap(); + const uboProgramMap = new WeakMap(); let enabledCapabilities = {}; @@ -21026,6 +22432,8 @@ let currentBlendEquationAlpha = null; let currentBlendSrcAlpha = null; let currentBlendDstAlpha = null; + let currentBlendColor = new Color( 0, 0, 0 ); + let currentBlendAlpha = 0; let currentPremultipledAlpha = false; let currentFlipSided = null; @@ -21036,11 +22444,11 @@ let currentPolygonOffsetFactor = null; let currentPolygonOffsetUnits = null; - const maxTextures = gl.getParameter( 35661 ); + const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS ); let lineWidthAvailable = false; let version = 0; - const glVersion = gl.getParameter( 7938 ); + const glVersion = gl.getParameter( gl.VERSION ); if ( glVersion.indexOf( 'WebGL' ) !== - 1 ) { @@ -21057,24 +22465,32 @@ let currentTextureSlot = null; let currentBoundTextures = {}; - const scissorParam = gl.getParameter( 3088 ); - const viewportParam = gl.getParameter( 2978 ); + const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); + const viewportParam = gl.getParameter( gl.VIEWPORT ); const currentScissor = new Vector4().fromArray( scissorParam ); const currentViewport = new Vector4().fromArray( viewportParam ); - function createTexture( type, target, count ) { + function createTexture( type, target, count, dimensions ) { const data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4. const texture = gl.createTexture(); gl.bindTexture( type, texture ); - gl.texParameteri( type, 10241, 9728 ); - gl.texParameteri( type, 10240, 9728 ); + gl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); for ( let i = 0; i < count; i ++ ) { - gl.texImage2D( target + i, 0, 6408, 1, 1, 0, 6408, 5121, data ); + if ( isWebGL2 && ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) ) { + + gl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } else { + + gl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data ); + + } } @@ -21083,8 +22499,15 @@ } const emptyTextures = {}; - emptyTextures[ 3553 ] = createTexture( 3553, 3553, 1 ); - emptyTextures[ 34067 ] = createTexture( 34067, 34069, 6 ); + emptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 ); + emptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 ); + + if ( isWebGL2 ) { + + emptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 ); + emptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 ); + + } // init @@ -21092,12 +22515,12 @@ depthBuffer.setClear( 1 ); stencilBuffer.setClear( 0 ); - enable( 2929 ); + enable( gl.DEPTH_TEST ); depthBuffer.setFunc( LessEqualDepth ); setFlipSided( false ); setCullFace( CullFaceBack ); - enable( 2884 ); + enable( gl.CULL_FACE ); setBlending( NoBlending ); @@ -21135,17 +22558,17 @@ if ( isWebGL2 ) { - // 36009 is equivalent to 36160 + // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER - if ( target === 36009 ) { + if ( target === gl.DRAW_FRAMEBUFFER ) { - currentBoundFramebuffers[ 36160 ] = framebuffer; + currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer; } - if ( target === 36160 ) { + if ( target === gl.FRAMEBUFFER ) { - currentBoundFramebuffers[ 36009 ] = framebuffer; + currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer; } @@ -21180,11 +22603,11 @@ const textures = renderTarget.texture; - if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { for ( let i = 0, il = textures.length; i < il; i ++ ) { - drawBuffers[ i ] = 36064 + i; + drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i; } @@ -21196,9 +22619,9 @@ } else { - if ( drawBuffers[ 0 ] !== 36064 ) { + if ( drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) { - drawBuffers[ 0 ] = 36064; + drawBuffers[ 0 ] = gl.COLOR_ATTACHMENT0; needsUpdate = true; @@ -21208,9 +22631,9 @@ } else { - if ( drawBuffers[ 0 ] !== 1029 ) { + if ( drawBuffers[ 0 ] !== gl.BACK ) { - drawBuffers[ 0 ] = 1029; + drawBuffers[ 0 ] = gl.BACK; needsUpdate = true; @@ -21252,15 +22675,15 @@ } const equationToGL = { - [ AddEquation ]: 32774, - [ SubtractEquation ]: 32778, - [ ReverseSubtractEquation ]: 32779 + [ AddEquation ]: gl.FUNC_ADD, + [ SubtractEquation ]: gl.FUNC_SUBTRACT, + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT }; if ( isWebGL2 ) { - equationToGL[ MinEquation ] = 32775; - equationToGL[ MaxEquation ] = 32776; + equationToGL[ MinEquation ] = gl.MIN; + equationToGL[ MaxEquation ] = gl.MAX; } else { @@ -21276,26 +22699,30 @@ } const factorToGL = { - [ ZeroFactor ]: 0, - [ OneFactor ]: 1, - [ SrcColorFactor ]: 768, - [ SrcAlphaFactor ]: 770, - [ SrcAlphaSaturateFactor ]: 776, - [ DstColorFactor ]: 774, - [ DstAlphaFactor ]: 772, - [ OneMinusSrcColorFactor ]: 769, - [ OneMinusSrcAlphaFactor ]: 771, - [ OneMinusDstColorFactor ]: 775, - [ OneMinusDstAlphaFactor ]: 773 + [ 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 }; - function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { if ( blending === NoBlending ) { if ( currentBlendingEnabled === true ) { - disable( 3042 ); + disable( gl.BLEND ); currentBlendingEnabled = false; } @@ -21306,7 +22733,7 @@ if ( currentBlendingEnabled === false ) { - enable( 3042 ); + enable( gl.BLEND ); currentBlendingEnabled = true; } @@ -21317,7 +22744,7 @@ if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) { - gl.blendEquation( 32774 ); + gl.blendEquation( gl.FUNC_ADD ); currentBlendEquation = AddEquation; currentBlendEquationAlpha = AddEquation; @@ -21329,19 +22756,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 1, 771, 1, 771 ); + gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 1, 1 ); + gl.blendFunc( gl.ONE, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFuncSeparate( 0, 768, 0, 770 ); + gl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA ); break; default: @@ -21355,19 +22782,19 @@ switch ( blending ) { case NormalBlending: - gl.blendFuncSeparate( 770, 771, 1, 771 ); + gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA ); break; case AdditiveBlending: - gl.blendFunc( 770, 1 ); + gl.blendFunc( gl.SRC_ALPHA, gl.ONE ); break; case SubtractiveBlending: - gl.blendFuncSeparate( 0, 769, 0, 1 ); + gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE ); break; case MultiplyBlending: - gl.blendFunc( 0, 768 ); + gl.blendFunc( gl.ZERO, gl.SRC_COLOR ); break; default: @@ -21382,6 +22809,8 @@ currentBlendDst = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor.set( 0, 0, 0 ); + currentBlendAlpha = 0; currentBlending = blending; currentPremultipledAlpha = premultipliedAlpha; @@ -21418,6 +22847,15 @@ } + if ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) { + + gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); + + currentBlendColor.copy( blendColor ); + currentBlendAlpha = blendAlpha; + + } + currentBlending = blending; currentPremultipledAlpha = false; @@ -21426,8 +22864,8 @@ function setMaterial( material, frontFaceCW ) { material.side === DoubleSide - ? disable( 2884 ) - : enable( 2884 ); + ? disable( gl.CULL_FACE ) + : enable( gl.CULL_FACE ); let flipSided = ( material.side === BackSide ); if ( frontFaceCW ) flipSided = ! flipSided; @@ -21436,7 +22874,7 @@ ( material.blending === NormalBlending && material.transparent === false ) ? setBlending( NoBlending ) - : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + : setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); depthBuffer.setFunc( material.depthFunc ); depthBuffer.setTest( material.depthTest ); @@ -21456,8 +22894,8 @@ setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); material.alphaToCoverage === true - ? enable( 32926 ) - : disable( 32926 ); + ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE ) + : disable( gl.SAMPLE_ALPHA_TO_COVERAGE ); } @@ -21469,11 +22907,11 @@ if ( flipSided ) { - gl.frontFace( 2304 ); + gl.frontFace( gl.CW ); } else { - gl.frontFace( 2305 ); + gl.frontFace( gl.CCW ); } @@ -21487,21 +22925,21 @@ if ( cullFace !== CullFaceNone ) { - enable( 2884 ); + enable( gl.CULL_FACE ); if ( cullFace !== currentCullFace ) { if ( cullFace === CullFaceBack ) { - gl.cullFace( 1029 ); + gl.cullFace( gl.BACK ); } else if ( cullFace === CullFaceFront ) { - gl.cullFace( 1028 ); + gl.cullFace( gl.FRONT ); } else { - gl.cullFace( 1032 ); + gl.cullFace( gl.FRONT_AND_BACK ); } @@ -21509,7 +22947,7 @@ } else { - disable( 2884 ); + disable( gl.CULL_FACE ); } @@ -21533,7 +22971,7 @@ if ( polygonOffset ) { - enable( 32823 ); + enable( gl.POLYGON_OFFSET_FILL ); if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) { @@ -21546,7 +22984,7 @@ } else { - disable( 32823 ); + disable( gl.POLYGON_OFFSET_FILL ); } @@ -21556,11 +22994,11 @@ if ( scissorTest ) { - enable( 3089 ); + enable( gl.SCISSOR_TEST ); } else { - disable( 3089 ); + disable( gl.SCISSOR_TEST ); } @@ -21570,7 +23008,7 @@ function activeTexture( webglSlot ) { - if ( webglSlot === undefined ) webglSlot = 33984 + maxTextures - 1; + if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1; if ( currentTextureSlot !== webglSlot ) { @@ -21587,7 +23025,7 @@ if ( currentTextureSlot === null ) { - webglSlot = 33984 + maxTextures - 1; + webglSlot = gl.TEXTURE0 + maxTextures - 1; } else { @@ -21805,13 +23243,13 @@ function updateUBOMapping( uniformsGroup, program ) { - let mapping = uboProgamMap.get( program ); + let mapping = uboProgramMap.get( program ); if ( mapping === undefined ) { mapping = new WeakMap(); - uboProgamMap.set( program, mapping ); + uboProgramMap.set( program, mapping ); } @@ -21829,16 +23267,15 @@ function uniformBlockBinding( uniformsGroup, program ) { - const mapping = uboProgamMap.get( program ); + const mapping = uboProgramMap.get( program ); const blockIndex = mapping.get( uniformsGroup ); - if ( uboBindings.get( uniformsGroup ) !== blockIndex ) { + if ( uboBindings.get( program ) !== blockIndex ) { // bind shader specific block index to global block point - gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex ); - uboBindings.set( uniformsGroup, blockIndex ); + uboBindings.set( program, blockIndex ); } @@ -21850,43 +23287,44 @@ // reset state - gl.disable( 3042 ); - gl.disable( 2884 ); - gl.disable( 2929 ); - gl.disable( 32823 ); - gl.disable( 3089 ); - gl.disable( 2960 ); - gl.disable( 32926 ); + 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( 32774 ); - gl.blendFunc( 1, 0 ); - gl.blendFuncSeparate( 1, 0, 1, 0 ); + 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.colorMask( true, true, true, true ); gl.clearColor( 0, 0, 0, 0 ); gl.depthMask( true ); - gl.depthFunc( 513 ); + gl.depthFunc( gl.LESS ); gl.clearDepth( 1 ); gl.stencilMask( 0xffffffff ); - gl.stencilFunc( 519, 0, 0xffffffff ); - gl.stencilOp( 7680, 7680, 7680 ); + gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff ); + gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP ); gl.clearStencil( 0 ); - gl.cullFace( 1029 ); - gl.frontFace( 2305 ); + gl.cullFace( gl.BACK ); + gl.frontFace( gl.CCW ); gl.polygonOffset( 0, 0 ); - gl.activeTexture( 33984 ); + gl.activeTexture( gl.TEXTURE0 ); - gl.bindFramebuffer( 36160, null ); + gl.bindFramebuffer( gl.FRAMEBUFFER, null ); if ( isWebGL2 === true ) { - gl.bindFramebuffer( 36009, null ); - gl.bindFramebuffer( 36008, null ); + gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null ); + gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null ); } @@ -21918,6 +23356,8 @@ currentBlendEquationAlpha = null; currentBlendSrcAlpha = null; currentBlendDstAlpha = null; + currentBlendColor = new Color( 0, 0, 0 ); + currentBlendAlpha = 0; currentPremultipledAlpha = false; currentFlipSided = null; @@ -21994,10 +23434,6 @@ function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) { const isWebGL2 = capabilities.isWebGL2; - const maxTextures = capabilities.maxTextures; - const maxCubemapSize = capabilities.maxCubemapSize; - const maxTextureSize = capabilities.maxTextureSize; - const maxSamples = capabilities.maxSamples; const multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null; const supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent ); @@ -22123,7 +23559,7 @@ } - function getInternalFormat( internalFormatName, glFormat, glType, encoding, forceLinearEncoding = false ) { + function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) { if ( isWebGL2 === false ) return glFormat; @@ -22137,35 +23573,48 @@ let internalFormat = glFormat; - if ( glFormat === 6403 ) { + if ( glFormat === _gl.RED ) { + + if ( glType === _gl.FLOAT ) internalFormat = _gl.R32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8; + + } + + if ( glFormat === _gl.RED_INTEGER ) { - if ( glType === 5126 ) internalFormat = 33326; - if ( glType === 5131 ) internalFormat = 33325; - if ( glType === 5121 ) internalFormat = 33321; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI; + if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI; + if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI; + if ( glType === _gl.BYTE ) internalFormat = _gl.R8I; + if ( glType === _gl.SHORT ) internalFormat = _gl.R16I; + if ( glType === _gl.INT ) internalFormat = _gl.R32I; } - if ( glFormat === 33319 ) { + if ( glFormat === _gl.RG ) { - if ( glType === 5126 ) internalFormat = 33328; - if ( glType === 5131 ) internalFormat = 33327; - if ( glType === 5121 ) internalFormat = 33323; + if ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8; } - if ( glFormat === 6408 ) { + if ( glFormat === _gl.RGBA ) { - if ( glType === 5126 ) internalFormat = 34836; - if ( glType === 5131 ) internalFormat = 34842; - if ( glType === 5121 ) internalFormat = ( encoding === sRGBEncoding && forceLinearEncoding === false ) ? 35907 : 32856; - if ( glType === 32819 ) internalFormat = 32854; - if ( glType === 32820 ) internalFormat = 32855; + const transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace ); + + if ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F; + if ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F; + if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8; + if ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4; + if ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1; } - if ( internalFormat === 33325 || internalFormat === 33326 || - internalFormat === 33327 || internalFormat === 33328 || - internalFormat === 34842 || internalFormat === 34836 ) { + if ( internalFormat === _gl.R16F || internalFormat === _gl.R32F || + internalFormat === _gl.RG16F || internalFormat === _gl.RG32F || + internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) { extensions.get( 'EXT_color_buffer_float' ); @@ -22207,11 +23656,11 @@ if ( f === NearestFilter || f === NearestMipmapNearestFilter || f === NearestMipmapLinearFilter ) { - return 9728; + return _gl.NEAREST; } - return 9729; + return _gl.LINEAR; } @@ -22321,14 +23770,32 @@ for ( let i = 0; i < 6; i ++ ) { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] ); } } else { - _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + if ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) { + + for ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] ); + + } else { + + _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer ); + + } + if ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer ); if ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer ); @@ -22385,9 +23852,9 @@ const textureUnit = textureUnits; - if ( textureUnit >= maxTextures ) { + if ( textureUnit >= capabilities.maxTextures ) { - console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + maxTextures ); + console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures ); } @@ -22414,7 +23881,7 @@ array.push( texture.premultiplyAlpha ); array.push( texture.flipY ); array.push( texture.unpackAlignment ); - array.push( texture.encoding ); + array.push( texture.colorSpace ); return array.join(); @@ -22449,7 +23916,7 @@ } - state.bindTexture( 3553, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22464,7 +23931,7 @@ } - state.bindTexture( 35866, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22479,7 +23946,7 @@ } - state.bindTexture( 32879, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } @@ -22494,50 +23961,61 @@ } - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); } const wrappingToGL = { - [ RepeatWrapping ]: 10497, - [ ClampToEdgeWrapping ]: 33071, - [ MirroredRepeatWrapping ]: 33648 + [ RepeatWrapping ]: _gl.REPEAT, + [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE, + [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT }; const filterToGL = { - [ NearestFilter ]: 9728, - [ NearestMipmapNearestFilter ]: 9984, - [ NearestMipmapLinearFilter ]: 9986, + [ 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 + }; - [ LinearFilter ]: 9729, - [ LinearMipmapNearestFilter ]: 9985, - [ LinearMipmapLinearFilter ]: 9987 + 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 }; function setTextureParameters( textureType, texture, supportsMips ) { if ( supportsMips ) { - _gl.texParameteri( textureType, 10242, wrappingToGL[ texture.wrapS ] ); - _gl.texParameteri( textureType, 10243, wrappingToGL[ texture.wrapT ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, wrappingToGL[ texture.wrapR ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] ); } - _gl.texParameteri( textureType, 10240, filterToGL[ texture.magFilter ] ); - _gl.texParameteri( textureType, 10241, filterToGL[ texture.minFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] ); } else { - _gl.texParameteri( textureType, 10242, 33071 ); - _gl.texParameteri( textureType, 10243, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); - if ( textureType === 32879 || textureType === 35866 ) { + if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) { - _gl.texParameteri( textureType, 32882, 33071 ); + _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, _gl.CLAMP_TO_EDGE ); } @@ -22547,8 +24025,8 @@ } - _gl.texParameteri( textureType, 10240, filterFallback( texture.magFilter ) ); - _gl.texParameteri( textureType, 10241, filterFallback( texture.minFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); + _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); if ( texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) { @@ -22558,10 +24036,19 @@ } + 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 ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) { const extension = extensions.get( 'EXT_texture_filter_anisotropic' ); + if ( texture.magFilter === NearestFilter ) return; + if ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return; if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension for WebGL 1 and WebGL 2 if ( isWebGL2 === false && ( texture.type === HalfFloatType && extensions.has( 'OES_texture_half_float_linear' ) === false ) ) return; // verify extension for WebGL 1 only @@ -22658,43 +24145,47 @@ function uploadTexture( textureProperties, texture, slot ) { - let textureType = 3553; + let textureType = _gl.TEXTURE_2D; - if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = 35866; - if ( texture.isData3DTexture ) textureType = 32879; + if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY; + if ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D; const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( textureType, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const needsPowerOfTwo = textureNeedsPowerOfTwo( texture ) && isPowerOfTwo$1( texture.image ) === false; - let image = resizeImage( texture.image, needsPowerOfTwo, false, maxTextureSize ); + let image = resizeImage( texture.image, needsPowerOfTwo, false, capabilities.maxTextureSize ); image = verifyColorSpace( texture, image ); const supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ); + glFormat = utils.convert( texture.format, texture.colorSpace ); let glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, texture.isVideoTexture ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture ); setTextureParameters( textureType, texture, supportsMips ); let mipmap; const mipmaps = texture.mipmaps; - const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); + const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true && glInternalFormat !== RGB_ETC1_Format ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); const levels = getMipLevels( texture, image, supportsMips ); @@ -22702,25 +24193,25 @@ // populate depth texture with dummy data - glInternalFormat = 6402; + glInternalFormat = _gl.DEPTH_COMPONENT; if ( isWebGL2 ) { if ( texture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( texture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } else if ( texture.type === UnsignedInt248Type ) { - glInternalFormat = 35056; + glInternalFormat = _gl.DEPTH24_STENCIL8; } else { - glInternalFormat = 33189; // WebGL2 requires sized internalformat for glTexImage2D + glInternalFormat = _gl.DEPTH_COMPONENT16; // WebGL2 requires sized internalformat for glTexImage2D } @@ -22736,7 +24227,7 @@ // validation checks for WebGL 1 - if ( texture.format === DepthFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_COMPONENT and type is not UNSIGNED_SHORT or UNSIGNED_INT @@ -22752,11 +24243,11 @@ } - if ( texture.format === DepthStencilFormat && glInternalFormat === 6402 ) { + if ( texture.format === DepthStencilFormat && glInternalFormat === _gl.DEPTH_COMPONENT ) { // Depth stencil textures need the DEPTH_STENCIL internal format // (https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/) - glInternalFormat = 34041; + glInternalFormat = _gl.DEPTH_STENCIL; // The error INVALID_OPERATION is generated by texImage2D if format and internalformat are // DEPTH_STENCIL and type is not UNSIGNED_INT_24_8_WEBGL. @@ -22778,11 +24269,11 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, 1, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null ); } @@ -22798,7 +24289,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22808,11 +24299,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22826,15 +24317,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data ); } else { - state.texImage2D( 3553, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data ); } @@ -22846,7 +24337,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth ); } @@ -22860,11 +24351,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); + state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 ); } else { - state.compressedTexImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); + state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 ); } @@ -22878,11 +24369,11 @@ if ( useTexStorage ) { - state.texSubImage3D( 35866, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data ); } else { - state.texImage3D( 35866, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data ); } @@ -22894,7 +24385,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -22908,11 +24399,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -22926,11 +24417,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 3553, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -22946,15 +24437,15 @@ if ( allocateMemory ) { - state.texStorage3D( 35866, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 35866, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 35866, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22964,15 +24455,15 @@ if ( allocateMemory ) { - state.texStorage3D( 32879, levels, glInternalFormat, image.width, image.height, image.depth ); + state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth ); } - state.texSubImage3D( 32879, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); + state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data ); } else { - state.texImage3D( 32879, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); + state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data ); } @@ -22982,7 +24473,7 @@ if ( useTexStorage ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } else { @@ -22990,7 +24481,7 @@ for ( let i = 0; i < levels; i ++ ) { - state.texImage2D( 3553, i, glInternalFormat, width, height, 0, glFormat, glType, null ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null ); width >>= 1; height >>= 1; @@ -23013,7 +24504,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height ); } @@ -23023,11 +24514,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 3553, i, 0, 0, glFormat, glType, mipmap ); + state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap ); } else { - state.texImage2D( 3553, i, glInternalFormat, glFormat, glType, mipmap ); + state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap ); } @@ -23041,15 +24532,15 @@ if ( allocateMemory ) { - state.texStorage2D( 3553, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height ); } - state.texSubImage2D( 3553, 0, 0, 0, glFormat, glType, image ); + state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image ); } else { - state.texImage2D( 3553, 0, glInternalFormat, glFormat, glType, image ); + state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image ); } @@ -23080,18 +24571,22 @@ const forceUpload = initTexture( textureProperties, texture ); const source = texture.source; - state.bindTexture( 34067, textureProperties.__webglTexture, 33984 + slot ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot ); const sourceProperties = properties.get( source ); if ( source.version !== sourceProperties.__version || forceUpload === true ) { - state.activeTexture( 33984 + slot ); + state.activeTexture( _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; - _gl.pixelStorei( 37440, texture.flipY ); - _gl.pixelStorei( 37441, texture.premultiplyAlpha ); - _gl.pixelStorei( 3317, texture.unpackAlignment ); - _gl.pixelStorei( 37443, 0 ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); + _gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion ); const isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture ); const isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture ); @@ -23102,7 +24597,7 @@ if ( ! isCompressed && ! isDataTexture ) { - cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, maxCubemapSize ); + cubeImage[ i ] = resizeImage( texture.image[ i ], false, true, capabilities.maxCubemapSize ); } else { @@ -23116,15 +24611,15 @@ const image = cubeImage[ 0 ], supportsMips = isPowerOfTwo$1( image ) || isWebGL2, - glFormat = utils.convert( texture.format, texture.encoding ), + glFormat = utils.convert( texture.format, texture.colorSpace ), glType = utils.convert( texture.type ), - glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const useTexStorage = ( isWebGL2 && texture.isVideoTexture !== true ); const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true ); let levels = getMipLevels( texture, image, supportsMips ); - setTextureParameters( 34067, texture, supportsMips ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); let mipmaps; @@ -23132,7 +24627,7 @@ if ( useTexStorage && allocateMemory ) { - state.texStorage2D( 34067, levels, glInternalFormat, image.width, image.height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height ); } @@ -23150,11 +24645,11 @@ if ( useTexStorage ) { - state.compressedTexSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); + state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data ); } else { - state.compressedTexImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); + state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } @@ -23168,11 +24663,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data ); } else { - state.texImage2D( 34069 + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } @@ -23194,7 +24689,7 @@ if ( mipmaps.length > 0 ) levels ++; - state.texStorage2D( 34067, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); + state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, cubeImage[ 0 ].width, cubeImage[ 0 ].height ); } @@ -23204,11 +24699,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data ); } @@ -23219,11 +24714,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data ); } @@ -23233,11 +24728,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] ); } else { - state.texImage2D( 34069 + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] ); } @@ -23247,11 +24742,11 @@ if ( useTexStorage ) { - state.texSubImage2D( 34069 + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); + state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] ); } else { - state.texImage2D( 34069 + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); + state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] ); } @@ -23266,7 +24761,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { // We assume images for cube map have the same size. - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23283,40 +24778,43 @@ // Render targets // Setup storage for target texture and bind it to correct framebuffer - function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget ) { + function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) { - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const renderTargetProperties = properties.get( renderTarget ); if ( ! renderTargetProperties.__hasExternalTextures ) { - if ( textureTarget === 32879 || textureTarget === 35866 ) { + const width = Math.max( 1, renderTarget.width >> level ); + const height = Math.max( 1, renderTarget.height >> level ); - state.texImage3D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, renderTarget.depth, 0, glFormat, glType, null ); + if ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) { + + state.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null ); } else { - state.texImage2D( textureTarget, 0, glInternalFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); + state.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null ); } } - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) ); - } else if ( textureTarget === 3553 || ( textureTarget >= 34069 && textureTarget <= 34074 ) ) { // see #24753 + } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753 - _gl.framebufferTexture2D( 36160, attachment, textureTarget, properties.get( texture ).__webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level ); } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23324,11 +24822,11 @@ // Setup storage for internal depth/stencil buffers and bind to correct framebuffer function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) { - _gl.bindRenderbuffer( 36161, renderbuffer ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { - let glInternalFormat = 33189; + let glInternalFormat = ( isWebGL2 === true ) ? _gl.DEPTH_COMPONENT24 : _gl.DEPTH_COMPONENT16; if ( isMultisample || useMultisampledRTT( renderTarget ) ) { @@ -23338,11 +24836,11 @@ if ( depthTexture.type === FloatType ) { - glInternalFormat = 36012; + glInternalFormat = _gl.DEPTH_COMPONENT32F; } else if ( depthTexture.type === UnsignedIntType ) { - glInternalFormat = 33190; + glInternalFormat = _gl.DEPTH_COMPONENT24; } @@ -23352,21 +24850,21 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 36096, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { @@ -23374,20 +24872,20 @@ if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, 35056, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, _gl.DEPTH24_STENCIL8, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, 34041, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); } - _gl.framebufferRenderbuffer( 36160, 33306, 36161, renderbuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else { @@ -23397,22 +24895,22 @@ const texture = textures[ i ]; - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace ); const samples = getRenderTargetSamples( renderTarget ); if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) { - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.renderbufferStorageMultisampleEXT( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); } else { - _gl.renderbufferStorage( 36161, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height ); } @@ -23420,7 +24918,7 @@ } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); } @@ -23430,7 +24928,7 @@ const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget ); if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' ); - state.bindFramebuffer( 36160, framebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) { @@ -23458,11 +24956,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 36096, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 36096, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23470,11 +24968,11 @@ if ( useMultisampledRTT( renderTarget ) ) { - multisampledRTTExt.framebufferTexture2DMultisampleEXT( 36160, 33306, 3553, webglDepthTexture, 0, samples ); + multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples ); } else { - _gl.framebufferTexture2D( 36160, 33306, 3553, webglDepthTexture, 0 ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 ); } @@ -23506,7 +25004,7 @@ for ( let i = 0; i < 6; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer[ i ] ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] ); renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false ); @@ -23514,7 +25012,7 @@ } else { - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer(); setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false ); @@ -23522,7 +25020,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23533,7 +25031,7 @@ if ( colorTexture !== undefined ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, 36064, 3553 ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 ); } @@ -23580,13 +25078,41 @@ for ( let i = 0; i < 6; i ++ ) { - renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer[ i ] = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer(); + + } } } else { - renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + renderTargetProperties.__webglFramebuffer = []; + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + renderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer(); + + } + + } else { + + renderTargetProperties.__webglFramebuffer = _gl.createFramebuffer(); + + } if ( isMultipleRenderTargets ) { @@ -23623,26 +25149,26 @@ renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer(); renderTargetProperties.__webglColorRenderbuffer = []; - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { const texture = textures[ i ]; renderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer(); - _gl.bindRenderbuffer( 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); - const glFormat = utils.convert( texture.format, texture.encoding ); + const glFormat = utils.convert( texture.format, texture.colorSpace ); const glType = utils.convert( texture.type ); - const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.encoding, renderTarget.isXRRenderTarget === true ); + const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true ); const samples = getRenderTargetSamples( renderTarget ); - _gl.renderbufferStorageMultisample( 36161, samples, glInternalFormat, renderTarget.width, renderTarget.height ); + _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } - _gl.bindRenderbuffer( 36161, null ); + _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); if ( renderTarget.depthBuffer ) { @@ -23651,7 +25177,7 @@ } - state.bindFramebuffer( 36160, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); } @@ -23661,18 +25187,30 @@ if ( isCube ) { - state.bindTexture( 34067, textureProperties.__webglTexture ); - setTextureParameters( 34067, texture, supportsMips ); + state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, supportsMips ); for ( let i = 0; i < 6; i ++ ) { - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, 36064, 34069 + i ); + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + 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, supportsMips ) ) { - generateMipmap( 34067 ); + generateMipmap( _gl.TEXTURE_CUBE_MAP ); } @@ -23687,13 +25225,13 @@ const attachment = textures[ i ]; const attachmentProperties = properties.get( attachment ); - state.bindTexture( 3553, attachmentProperties.__webglTexture ); - setTextureParameters( 3553, attachment, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, 36064 + i, 3553 ); + state.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture ); + setTextureParameters( _gl.TEXTURE_2D, attachment, supportsMips ); + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 ); if ( textureNeedsGenerateMipmaps( attachment, supportsMips ) ) { - generateMipmap( 3553 ); + generateMipmap( _gl.TEXTURE_2D ); } @@ -23703,13 +25241,13 @@ } else { - let glTextureType = 3553; + let glTextureType = _gl.TEXTURE_2D; if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) { if ( isWebGL2 ) { - glTextureType = renderTarget.isWebGL3DRenderTarget ? 32879 : 35866; + glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY; } else { @@ -23721,7 +25259,20 @@ state.bindTexture( glTextureType, textureProperties.__webglTexture ); setTextureParameters( glTextureType, texture, supportsMips ); - setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, 36064, glTextureType ); + + if ( isWebGL2 && texture.mipmaps && texture.mipmaps.length > 0 ) { + + for ( let level = 0; level < texture.mipmaps.length; level ++ ) { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level ); + + } + + } else { + + setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 ); + + } if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { @@ -23755,7 +25306,7 @@ if ( textureNeedsGenerateMipmaps( texture, supportsMips ) ) { - const target = renderTarget.isWebGLCubeRenderTarget ? 34067 : 3553; + const target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D; const webglTexture = properties.get( texture ).__webglTexture; state.bindTexture( target, webglTexture ); @@ -23775,9 +25326,9 @@ const textures = renderTarget.isWebGLMultipleRenderTargets ? renderTarget.texture : [ renderTarget.texture ]; const width = renderTarget.width; const height = renderTarget.height; - let mask = 16384; + let mask = _gl.COLOR_BUFFER_BIT; const invalidationArray = []; - const depthStyle = renderTarget.stencilBuffer ? 33306 : 36096; + const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT; const renderTargetProperties = properties.get( renderTarget ); const isMultipleRenderTargets = ( renderTarget.isWebGLMultipleRenderTargets === true ); @@ -23786,22 +25337,22 @@ for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, null ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null ); - state.bindFramebuffer( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, null, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 ); } } - state.bindFramebuffer( 36008, renderTargetProperties.__webglMultisampledFramebuffer ); - state.bindFramebuffer( 36009, renderTargetProperties.__webglFramebuffer ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); for ( let i = 0; i < textures.length; i ++ ) { - invalidationArray.push( 36064 + i ); + invalidationArray.push( _gl.COLOR_ATTACHMENT0 + i ); if ( renderTarget.depthBuffer ) { @@ -23813,63 +25364,63 @@ if ( ignoreDepthValues === false ) { - if ( renderTarget.depthBuffer ) mask |= 256; - if ( renderTarget.stencilBuffer ) mask |= 1024; + if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT; + if ( renderTarget.stencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT; } if ( isMultipleRenderTargets ) { - _gl.framebufferRenderbuffer( 36008, 36064, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] ); } if ( ignoreDepthValues === true ) { - _gl.invalidateFramebuffer( 36008, [ depthStyle ] ); - _gl.invalidateFramebuffer( 36009, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, [ depthStyle ] ); + _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] ); } if ( isMultipleRenderTargets ) { const webglTexture = properties.get( textures[ i ] ).__webglTexture; - _gl.framebufferTexture2D( 36009, 36064, 3553, webglTexture, 0 ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 ); } - _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, 9728 ); + _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST ); if ( supportsInvalidateFramebuffer ) { - _gl.invalidateFramebuffer( 36008, invalidationArray ); + _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArray ); } } - state.bindFramebuffer( 36008, null ); - state.bindFramebuffer( 36009, null ); + state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null ); // If MRT since pre-blit we removed the FBO we need to reconstruct the attachments if ( isMultipleRenderTargets ) { for ( let i = 0; i < textures.length; i ++ ) { - state.bindFramebuffer( 36160, renderTargetProperties.__webglMultisampledFramebuffer ); - _gl.framebufferRenderbuffer( 36160, 36064 + i, 36161, renderTargetProperties.__webglColorRenderbuffer[ i ] ); + 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( 36160, renderTargetProperties.__webglFramebuffer ); - _gl.framebufferTexture2D( 36009, 36064 + i, 3553, webglTexture, 0 ); + state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer ); + _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 ); } } - state.bindFramebuffer( 36009, renderTargetProperties.__webglMultisampledFramebuffer ); + state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer ); } @@ -23877,7 +25428,7 @@ function getRenderTargetSamples( renderTarget ) { - return Math.min( maxSamples, renderTarget.samples ); + return Math.min( capabilities.maxSamples, renderTarget.samples ); } @@ -23906,17 +25457,17 @@ function verifyColorSpace( texture, image ) { - const encoding = texture.encoding; + const colorSpace = texture.colorSpace; const format = texture.format; const type = texture.type; if ( texture.isCompressedTexture === true || texture.isVideoTexture === true || texture.format === _SRGBAFormat ) return image; - if ( encoding !== LinearEncoding ) { + if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) { // sRGB - if ( encoding === sRGBEncoding ) { + if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) { if ( isWebGL2 === false ) { @@ -23953,7 +25504,7 @@ } else { - console.error( 'THREE.WebGLTextures: Unsupported texture encoding:', encoding ); + console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace ); } @@ -23986,24 +25537,26 @@ const isWebGL2 = capabilities.isWebGL2; - function convert( p, encoding = null ) { + function convert( p, colorSpace = NoColorSpace ) { let extension; - if ( p === UnsignedByteType ) return 5121; - if ( p === UnsignedShort4444Type ) return 32819; - if ( p === UnsignedShort5551Type ) return 32820; + const transfer = ColorManagement.getTransfer( colorSpace ); - if ( p === ByteType ) return 5120; - if ( p === ShortType ) return 5122; - if ( p === UnsignedShortType ) return 5123; - if ( p === IntType ) return 5124; - if ( p === UnsignedIntType ) return 5125; - if ( p === FloatType ) return 5126; + if ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE; + if ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4; + if ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1; + + if ( p === ByteType ) return gl.BYTE; + if ( p === ShortType ) return gl.SHORT; + if ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT; + if ( p === IntType ) return gl.INT; + if ( p === UnsignedIntType ) return gl.UNSIGNED_INT; + if ( p === FloatType ) return gl.FLOAT; if ( p === HalfFloatType ) { - if ( isWebGL2 ) return 5131; + if ( isWebGL2 ) return gl.HALF_FLOAT; extension = extensions.get( 'OES_texture_half_float' ); @@ -24019,21 +25572,12 @@ } - if ( p === AlphaFormat ) return 6406; - if ( p === RGBAFormat ) return 6408; - if ( p === LuminanceFormat ) return 6409; - if ( p === LuminanceAlphaFormat ) return 6410; - if ( p === DepthFormat ) return 6402; - if ( p === DepthStencilFormat ) return 34041; - - // @deprecated since r137 - - if ( p === RGBFormat ) { - - console.warn( 'THREE.WebGLRenderer: THREE.RGBFormat has been removed. Use THREE.RGBAFormat instead. https://github.com/mrdoob/three.js/pull/23228' ); - return 6408; - - } + if ( p === AlphaFormat ) return gl.ALPHA; + if ( p === RGBAFormat ) return gl.RGBA; + if ( p === LuminanceFormat ) return gl.LUMINANCE; + if ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA; + if ( p === DepthFormat ) return gl.DEPTH_COMPONENT; + if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL; // WebGL 1 sRGB fallback @@ -24055,17 +25599,17 @@ // WebGL2 formats. - if ( p === RedFormat ) return 6403; - if ( p === RedIntegerFormat ) return 36244; - if ( p === RGFormat ) return 33319; - if ( p === RGIntegerFormat ) return 33320; - if ( p === RGBAIntegerFormat ) return 36249; + if ( p === RedFormat ) return gl.RED; + if ( p === RedIntegerFormat ) return gl.RED_INTEGER; + if ( p === RGFormat ) return gl.RG; + if ( p === RGIntegerFormat ) return gl.RG_INTEGER; + if ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER; // S3TC if ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) { - if ( encoding === sRGBEncoding ) { + if ( transfer === SRGBTransfer ) { extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' ); @@ -24150,8 +25694,8 @@ if ( extension !== null ) { - if ( p === RGB_ETC2_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; - if ( p === RGBA_ETC2_EAC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; + if ( p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2; + if ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC; } else { @@ -24173,20 +25717,20 @@ if ( extension !== null ) { - if ( p === RGBA_ASTC_4x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; - if ( p === RGBA_ASTC_5x4_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; - if ( p === RGBA_ASTC_5x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; - if ( p === RGBA_ASTC_6x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; - if ( p === RGBA_ASTC_6x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; - if ( p === RGBA_ASTC_8x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; - if ( p === RGBA_ASTC_8x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; - if ( p === RGBA_ASTC_8x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; - if ( p === RGBA_ASTC_10x5_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; - if ( p === RGBA_ASTC_10x6_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; - if ( p === RGBA_ASTC_10x8_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; - if ( p === RGBA_ASTC_10x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; - if ( p === RGBA_ASTC_12x10_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; - if ( p === RGBA_ASTC_12x12_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; + if ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR; + if ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR; + if ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR; + if ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR; + if ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR; + if ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR; + if ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR; + if ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR; + if ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR; + if ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR; + if ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR; + if ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR; + if ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR; + if ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR; } else { @@ -24198,13 +25742,36 @@ // BPTC - if ( p === RGBA_BPTC_Format ) { + if ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) { extension = extensions.get( 'EXT_texture_compression_bptc' ); if ( extension !== null ) { - if ( p === RGBA_BPTC_Format ) return ( encoding === sRGBEncoding ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT; + if ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT; + if ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT; + + } else { + + return null; + + } + + } + + // RGTC + + if ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) { + + extension = extensions.get( 'EXT_texture_compression_rgtc' ); + + if ( extension !== null ) { + + if ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT; + if ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT; + if ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT; + if ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT; } else { @@ -24218,7 +25785,7 @@ if ( p === UnsignedInt248Type ) { - if ( isWebGL2 ) return 34042; + if ( isWebGL2 ) return gl.UNSIGNED_INT_24_8; extension = extensions.get( 'WEBGL_depth_texture' ); @@ -24440,6 +26007,7 @@ joint.matrix.fromArray( jointPose.transform.matrix ); joint.matrix.decompose( joint.position, joint.rotation, joint.scale ); + joint.matrixWorldNeedsUpdate = true; joint.jointRadius = jointPose.radius; } @@ -24488,6 +26056,7 @@ grip.matrix.fromArray( gripPose.transform.matrix ); grip.matrix.decompose( grip.position, grip.rotation, grip.scale ); + grip.matrixWorldNeedsUpdate = true; if ( gripPose.linearVelocity ) { @@ -24532,6 +26101,7 @@ targetRay.matrix.fromArray( inputPose.transform.matrix ); targetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale ); + targetRay.matrixWorldNeedsUpdate = true; if ( inputPose.linearVelocity ) { @@ -24607,38 +26177,6 @@ } - class DepthTexture extends Texture { - - constructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format ) { - - format = format !== undefined ? format : DepthFormat; - - if ( format !== DepthFormat && format !== DepthStencilFormat ) { - - throw new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' ); - - } - - if ( type === undefined && format === DepthFormat ) type = UnsignedIntType; - if ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type; - - super( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); - - this.isDepthTexture = true; - - this.image = { width: width, height: height }; - - this.magFilter = magFilter !== undefined ? magFilter : NearestFilter; - this.minFilter = minFilter !== undefined ? minFilter : NearestFilter; - - this.flipY = false; - this.generateMipmaps = false; - - } - - - } - class WebXRManager extends EventDispatcher { constructor( renderer, gl ) { @@ -24648,10 +26186,13 @@ const scope = this; let session = null; + let framebufferScaleFactor = 1.0; let referenceSpace = null; let referenceSpaceType = 'local-floor'; + // Set default foveation to maximum. + let foveation = 1.0; let customReferenceSpace = null; let pose = null; @@ -24666,8 +26207,8 @@ const controllers = []; const controllerInputSources = []; - const planes = new Set(); - const planesLastChangedTimes = new Map(); + const currentSize = new Vector2(); + let currentPixelRatio = null; // @@ -24681,9 +26222,9 @@ const cameras = [ cameraL, cameraR ]; - const cameraVR = new ArrayCamera(); - cameraVR.layers.enable( 1 ); - cameraVR.layers.enable( 2 ); + const cameraXR = new ArrayCamera(); + cameraXR.layers.enable( 1 ); + cameraXR.layers.enable( 2 ); let _currentDepthNear = null; let _currentDepthFar = null; @@ -24756,6 +26297,7 @@ if ( controller !== undefined ) { + controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace ); controller.dispatchEvent( { type: event.type, data: event.inputSource } ); } @@ -24804,6 +26346,9 @@ scope.isPresenting = false; + renderer.setPixelRatio( currentPixelRatio ); + renderer.setSize( currentSize.width, currentSize.height, false ); + scope.dispatchEvent( { type: 'sessionend' } ); } @@ -24891,11 +26436,14 @@ } + currentPixelRatio = renderer.getPixelRatio(); + renderer.getSize( currentSize ); + if ( ( session.renderState.layers === undefined ) || ( renderer.capabilities.isWebGL2 === false ) ) { const layerInit = { antialias: ( session.renderState.layers === undefined ) ? attributes.antialias : true, - alpha: attributes.alpha, + alpha: true, depth: attributes.depth, stencil: attributes.stencil, framebufferScaleFactor: framebufferScaleFactor @@ -24905,13 +26453,16 @@ session.updateRenderState( { baseLayer: glBaseLayer } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false ); + newRenderTarget = new WebGLRenderTarget( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, { format: RGBAFormat, type: UnsignedByteType, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, stencilBuffer: attributes.stencil } ); @@ -24924,14 +26475,14 @@ if ( attributes.depth ) { - glDepthFormat = attributes.stencil ? 35056 : 33190; + glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24; depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat; depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType; } const projectionlayerInit = { - colorFormat: 32856, + colorFormat: gl.RGBA8, depthFormat: glDepthFormat, scaleFactor: framebufferScaleFactor }; @@ -24942,6 +26493,9 @@ session.updateRenderState( { layers: [ glProjLayer ] } ); + renderer.setPixelRatio( 1 ); + renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false ); + newRenderTarget = new WebGLRenderTarget( glProjLayer.textureWidth, glProjLayer.textureHeight, @@ -24950,7 +26504,7 @@ type: UnsignedByteType, depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ), stencilBuffer: attributes.stencil, - encoding: renderer.outputEncoding, + colorSpace: renderer.outputColorSpace, samples: attributes.antialias ? 4 : 0 } ); @@ -24961,8 +26515,7 @@ newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278 - // Set foveation to maximum. - this.setFoveation( 1.0 ); + this.setFoveation( foveation ); customReferenceSpace = null; referenceSpace = await session.requestReferenceSpace( referenceSpaceType ); @@ -24978,6 +26531,16 @@ }; + this.getEnvironmentBlendMode = function () { + + if ( session !== null ) { + + return session.environmentBlendMode; + + } + + }; + function onInputSourcesChange( event ) { // Notify disconnected @@ -25101,6 +26664,7 @@ const bottom2 = bottomFov * far / far2 * near2; camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); } @@ -25124,27 +26688,27 @@ if ( session === null ) return; - cameraVR.near = cameraR.near = cameraL.near = camera.near; - cameraVR.far = cameraR.far = cameraL.far = camera.far; + cameraXR.near = cameraR.near = cameraL.near = camera.near; + cameraXR.far = cameraR.far = cameraL.far = camera.far; - if ( _currentDepthNear !== cameraVR.near || _currentDepthFar !== cameraVR.far ) { + if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) { // Note that the new renderState won't apply until the next frame. See #18320 session.updateRenderState( { - depthNear: cameraVR.near, - depthFar: cameraVR.far + depthNear: cameraXR.near, + depthFar: cameraXR.far } ); - _currentDepthNear = cameraVR.near; - _currentDepthFar = cameraVR.far; + _currentDepthNear = cameraXR.near; + _currentDepthFar = cameraXR.far; } const parent = camera.parent; - const cameras = cameraVR.cameras; + const cameras = cameraXR.cameras; - updateCamera( cameraVR, parent ); + updateCamera( cameraXR, parent ); for ( let i = 0; i < cameras.length; i ++ ) { @@ -25152,86 +26716,94 @@ } - cameraVR.matrixWorld.decompose( cameraVR.position, cameraVR.quaternion, cameraVR.scale ); + // update projection matrix for proper view frustum culling - // update user camera and its children + if ( cameras.length === 2 ) { - camera.matrix.copy( cameraVR.matrix ); - camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + setProjectionFromUnion( cameraXR, cameraL, cameraR ); - const children = camera.children; + } else { - for ( let i = 0, l = children.length; i < l; i ++ ) { + // assume single camera setup (AR) - children[ i ].updateMatrixWorld( true ); + cameraXR.projectionMatrix.copy( cameraL.projectionMatrix ); } - // update projection matrix for proper view frustum culling + // update user camera and its children - if ( cameras.length === 2 ) { + updateUserCamera( camera, cameraXR, parent ); + + }; + + function updateUserCamera( camera, cameraXR, parent ) { - setProjectionFromUnion( cameraVR, cameraL, cameraR ); + if ( parent === null ) { + + camera.matrix.copy( cameraXR.matrixWorld ); } else { - // assume single camera setup (AR) + camera.matrix.copy( parent.matrixWorld ); + camera.matrix.invert(); + camera.matrix.multiply( cameraXR.matrixWorld ); + + } + + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); + camera.updateMatrixWorld( true ); + + camera.projectionMatrix.copy( cameraXR.projectionMatrix ); + camera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse ); - cameraVR.projectionMatrix.copy( cameraL.projectionMatrix ); + if ( camera.isPerspectiveCamera ) { + + camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] ); + camera.zoom = 1; } - }; + } this.getCamera = function () { - return cameraVR; + return cameraXR; }; this.getFoveation = function () { - if ( glProjLayer !== null ) { - - return glProjLayer.fixedFoveation; - - } - - if ( glBaseLayer !== null ) { + if ( glProjLayer === null && glBaseLayer === null ) { - return glBaseLayer.fixedFoveation; + return undefined; } - return undefined; + return foveation; }; - this.setFoveation = function ( foveation ) { + this.setFoveation = function ( value ) { // 0 = no foveation = full resolution // 1 = maximum foveation = the edges render at lower resolution + foveation = value; + if ( glProjLayer !== null ) { - glProjLayer.fixedFoveation = foveation; + glProjLayer.fixedFoveation = value; } if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) { - glBaseLayer.fixedFoveation = foveation; + glBaseLayer.fixedFoveation = value; } }; - this.getPlanes = function () { - - return planes; - - }; - // Animation Loop let onAnimationFrameCallback = null; @@ -25252,14 +26824,14 @@ } - let cameraVRNeedsUpdate = false; + let cameraXRNeedsUpdate = false; - // check if it's necessary to rebuild cameraVR's camera list + // check if it's necessary to rebuild cameraXR's camera list - if ( views.length !== cameraVR.cameras.length ) { + if ( views.length !== cameraXR.cameras.length ) { - cameraVR.cameras.length = 0; - cameraVRNeedsUpdate = true; + cameraXR.cameras.length = 0; + cameraXRNeedsUpdate = true; } @@ -25304,18 +26876,21 @@ } camera.matrix.fromArray( view.transform.matrix ); + camera.matrix.decompose( camera.position, camera.quaternion, camera.scale ); camera.projectionMatrix.fromArray( view.projectionMatrix ); + camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert(); camera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height ); if ( i === 0 ) { - cameraVR.matrix.copy( camera.matrix ); + cameraXR.matrix.copy( camera.matrix ); + cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale ); } - if ( cameraVRNeedsUpdate === true ) { + if ( cameraXRNeedsUpdate === true ) { - cameraVR.cameras.push( camera ); + cameraXR.cameras.push( camera ); } @@ -25342,60 +26917,7 @@ if ( frame.detectedPlanes ) { - scope.dispatchEvent( { type: 'planesdetected', data: frame.detectedPlanes } ); - - let planesToRemove = null; - - for ( const plane of planes ) { - - if ( ! frame.detectedPlanes.has( plane ) ) { - - if ( planesToRemove === null ) { - - planesToRemove = []; - - } - - planesToRemove.push( plane ); - - } - - } - - if ( planesToRemove !== null ) { - - for ( const plane of planesToRemove ) { - - planes.delete( plane ); - planesLastChangedTimes.delete( plane ); - scope.dispatchEvent( { type: 'planeremoved', data: plane } ); - - } - - } - - for ( const plane of frame.detectedPlanes ) { - - if ( ! planes.has( plane ) ) { - - planes.add( plane ); - planesLastChangedTimes.set( plane, frame.lastChangedTime ); - scope.dispatchEvent( { type: 'planeadded', data: plane } ); - - } else { - - const lastKnownTime = planesLastChangedTimes.get( plane ); - - if ( plane.lastChangedTime > lastKnownTime ) { - - planesLastChangedTimes.set( plane, plane.lastChangedTime ); - scope.dispatchEvent( { type: 'planechanged', data: plane } ); - - } - - } - - } + scope.dispatchEvent( { type: 'planesdetected', data: frame } ); } @@ -25421,6 +26943,18 @@ function WebGLMaterials( renderer, properties ) { + function refreshTransformUniform( map, uniform ) { + + if ( map.matrixAutoUpdate === true ) { + + map.updateMatrix(); + + } + + uniform.value.copy( map.matrix ); + + } + function refreshFogUniforms( uniforms, fog ) { fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) ); @@ -25538,25 +27072,56 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } 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; - if ( material.side === BackSide ) uniforms.bumpScale.value *= - 1; + + if ( material.side === BackSide ) { + + uniforms.bumpScale.value *= - 1; + + } + + } + + if ( material.normalMap ) { + + uniforms.normalMap.value = material.normalMap; + + refreshTransformUniform( material.normalMap, uniforms.normalMapTransform ); + + uniforms.normalScale.value.copy( material.normalScale ); + + if ( material.side === BackSide ) { + + 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; @@ -25566,13 +27131,7 @@ uniforms.emissiveMap.value = material.emissiveMap; - } - - if ( material.normalMap ) { - - uniforms.normalMap.value = material.normalMap; - uniforms.normalScale.value.copy( material.normalScale ); - if ( material.side === BackSide ) uniforms.normalScale.value.negate(); + refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform ); } @@ -25580,6 +27139,8 @@ uniforms.specularMap.value = material.specularMap; + refreshTransformUniform( material.specularMap, uniforms.specularMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25607,10 +27168,12 @@ uniforms.lightMap.value = material.lightMap; // artist-friendly light intensity scaling factor - const scaleFactor = ( renderer.physicallyCorrectLights !== true ) ? Math.PI : 1; + const scaleFactor = ( renderer._useLegacyLights === true ) ? Math.PI : 1; uniforms.lightMapIntensity.value = material.lightMapIntensity * scaleFactor; + refreshTransformUniform( material.lightMap, uniforms.lightMapTransform ); + } if ( material.aoMap ) { @@ -25618,175 +27181,27 @@ uniforms.aoMap.value = material.aoMap; uniforms.aoMapIntensity.value = material.aoMapIntensity; - } - - // uv repeat and offset setting priorities - // 1. color map - // 2. specular map - // 3. displacementMap map - // 4. normal map - // 5. bump map - // 6. roughnessMap map - // 7. metalnessMap map - // 8. alphaMap map - // 9. emissiveMap map - // 10. clearcoat map - // 11. clearcoat normal map - // 12. clearcoat roughnessMap map - // 13. iridescence map - // 14. iridescence thickness map - // 15. specular intensity map - // 16. specular tint map - // 17. transmission map - // 18. thickness map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.specularMap ) { - - uvScaleMap = material.specularMap; - - } else if ( material.displacementMap ) { - - uvScaleMap = material.displacementMap; - - } else if ( material.normalMap ) { - - uvScaleMap = material.normalMap; - - } else if ( material.bumpMap ) { - - uvScaleMap = material.bumpMap; - - } else if ( material.roughnessMap ) { - - uvScaleMap = material.roughnessMap; - - } else if ( material.metalnessMap ) { - - uvScaleMap = material.metalnessMap; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } else if ( material.emissiveMap ) { - - uvScaleMap = material.emissiveMap; - - } else if ( material.clearcoatMap ) { - - uvScaleMap = material.clearcoatMap; - - } else if ( material.clearcoatNormalMap ) { - - uvScaleMap = material.clearcoatNormalMap; - - } else if ( material.clearcoatRoughnessMap ) { - - uvScaleMap = material.clearcoatRoughnessMap; - - } else if ( material.iridescenceMap ) { - - uvScaleMap = material.iridescenceMap; - - } else if ( material.iridescenceThicknessMap ) { - - uvScaleMap = material.iridescenceThicknessMap; - - } else if ( material.specularIntensityMap ) { - - uvScaleMap = material.specularIntensityMap; - - } else if ( material.specularColorMap ) { - - uvScaleMap = material.specularColorMap; - - } else if ( material.transmissionMap ) { - - uvScaleMap = material.transmissionMap; - - } else if ( material.thicknessMap ) { - - uvScaleMap = material.thicknessMap; - - } else if ( material.sheenColorMap ) { - - uvScaleMap = material.sheenColorMap; - - } else if ( material.sheenRoughnessMap ) { - - uvScaleMap = material.sheenRoughnessMap; + refreshTransformUniform( material.aoMap, uniforms.aoMapTransform ); } - if ( uvScaleMap !== undefined ) { - - // backwards compatibility - if ( uvScaleMap.isWebGLRenderTarget ) { - - uvScaleMap = uvScaleMap.texture; - - } - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - - // uv repeat and offset setting priorities for uv2 - // 1. ao map - // 2. light map - - let uv2ScaleMap; - - if ( material.aoMap ) { - - uv2ScaleMap = material.aoMap; - - } else if ( material.lightMap ) { - - uv2ScaleMap = material.lightMap; - - } - - if ( uv2ScaleMap !== undefined ) { - - // backwards compatibility - if ( uv2ScaleMap.isWebGLRenderTarget ) { - - uv2ScaleMap = uv2ScaleMap.texture; + } - } + function refreshUniformsLine( uniforms, material ) { - if ( uv2ScaleMap.matrixAutoUpdate === true ) { + uniforms.diffuse.value.copy( material.color ); + uniforms.opacity.value = material.opacity; - uv2ScaleMap.updateMatrix(); + if ( material.map ) { - } + uniforms.map.value = material.map; - uniforms.uv2Transform.value.copy( uv2ScaleMap.matrix ); + refreshTransformUniform( material.map, uniforms.mapTransform ); } } - function refreshUniformsLine( uniforms, material ) { - - uniforms.diffuse.value.copy( material.color ); - uniforms.opacity.value = material.opacity; - - } - function refreshUniformsDash( uniforms, material ) { uniforms.dashSize.value = material.dashSize; @@ -25806,12 +27221,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.uvTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25820,34 +27239,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsSprites( uniforms, material ) { @@ -25860,12 +27251,16 @@ uniforms.map.value = material.map; + refreshTransformUniform( material.map, uniforms.mapTransform ); + } if ( material.alphaMap ) { uniforms.alphaMap.value = material.alphaMap; + refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform ); + } if ( material.alphaTest > 0 ) { @@ -25874,34 +27269,6 @@ } - // uv repeat and offset setting priorities - // 1. color map - // 2. alpha map - - let uvScaleMap; - - if ( material.map ) { - - uvScaleMap = material.map; - - } else if ( material.alphaMap ) { - - uvScaleMap = material.alphaMap; - - } - - if ( uvScaleMap !== undefined ) { - - if ( uvScaleMap.matrixAutoUpdate === true ) { - - uvScaleMap.updateMatrix(); - - } - - uniforms.uvTransform.value.copy( uvScaleMap.matrix ); - - } - } function refreshUniformsPhong( uniforms, material ) { @@ -25923,18 +27290,23 @@ function refreshUniformsStandard( uniforms, material ) { - uniforms.roughness.value = material.roughness; uniforms.metalness.value = material.metalness; - if ( material.roughnessMap ) { + if ( material.metalnessMap ) { - uniforms.roughnessMap.value = material.roughnessMap; + uniforms.metalnessMap.value = material.metalnessMap; + + refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform ); } - if ( material.metalnessMap ) { + uniforms.roughness.value = material.roughness; - uniforms.metalnessMap.value = material.metalnessMap; + if ( material.roughnessMap ) { + + uniforms.roughnessMap.value = material.roughnessMap; + + refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform ); } @@ -25963,12 +27335,16 @@ uniforms.sheenColorMap.value = material.sheenColorMap; + refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform ); + } if ( material.sheenRoughnessMap ) { uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap; + refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform ); + } } @@ -25982,18 +27358,25 @@ 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 ) { + if ( material.clearcoatNormalMap ) { + + uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; + + refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform ); uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale ); - uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap; if ( material.side === BackSide ) { @@ -26016,12 +27399,16 @@ uniforms.iridescenceMap.value = material.iridescenceMap; + refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform ); + } if ( material.iridescenceThicknessMap ) { uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap; + refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform ); + } } @@ -26036,6 +27423,8 @@ uniforms.transmissionMap.value = material.transmissionMap; + refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform ); + } uniforms.thickness.value = material.thickness; @@ -26044,6 +27433,8 @@ uniforms.thicknessMap.value = material.thicknessMap; + refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform ); + } uniforms.attenuationDistance.value = material.attenuationDistance; @@ -26051,19 +27442,37 @@ } - uniforms.specularIntensity.value = material.specularIntensity; - uniforms.specularColor.value.copy( material.specularColor ); + if ( material.anisotropy > 0 ) { - if ( material.specularIntensityMap ) { + uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) ); - uniforms.specularIntensityMap.value = material.specularIntensityMap; + 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 ); + } } @@ -26080,9 +27489,11 @@ function refreshUniformsDistance( uniforms, material ) { - uniforms.referencePosition.value.copy( material.referencePosition ); - uniforms.nearDistance.value = material.nearDistance; - uniforms.farDistance.value = material.farDistance; + const light = properties.get( material ).light; + + uniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld ); + uniforms.nearDistance.value = light.shadow.camera.near; + uniforms.farDistance.value = light.shadow.camera.far; } @@ -26099,7 +27510,7 @@ let updateList = {}; let allocatedBindingPoints = []; - const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( 35375 ) : 0; // binding points are global whereas block indices are per shader program + const maxBindingPoints = ( capabilities.isWebGL2 ) ? gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ) : 0; // binding points are global whereas block indices are per shader program function bind( uniformsGroup, program ) { @@ -26153,10 +27564,10 @@ const size = uniformsGroup.__size; const usage = uniformsGroup.usage; - gl.bindBuffer( 35345, buffer ); - gl.bufferData( 35345, size, usage ); - gl.bindBuffer( 35345, null ); - gl.bindBufferBase( 35345, bindingPointIndex, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); + gl.bufferData( gl.UNIFORM_BUFFER, size, usage ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); + gl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer ); return buffer; @@ -26187,50 +27598,64 @@ const uniforms = uniformsGroup.uniforms; const cache = uniformsGroup.__cache; - gl.bindBuffer( 35345, buffer ); + gl.bindBuffer( gl.UNIFORM_BUFFER, buffer ); for ( let i = 0, il = uniforms.length; i < il; i ++ ) { - const uniform = uniforms[ i ]; + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // partly update the buffer if necessary + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - if ( hasUniformChanged( uniform, i, cache ) === true ) { + const uniform = uniformArray[ j ]; - const value = uniform.value; - const offset = uniform.__offset; + if ( hasUniformChanged( uniform, i, j, cache ) === true ) { - if ( typeof value === 'number' ) { + const offset = uniform.__offset; - uniform.__data[ 0 ] = value; - gl.bufferSubData( 35345, offset, uniform.__data ); + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; - } else { + let arrayOffset = 0; - if ( uniform.value.isMatrix3 ) { + for ( let k = 0; k < values.length; k ++ ) { - // manually converting 3x3 to 3x4 + const value = values[ k ]; - uniform.__data[ 0 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 1 ] = uniform.value.elements[ 1 ]; - uniform.__data[ 2 ] = uniform.value.elements[ 2 ]; - uniform.__data[ 3 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 4 ] = uniform.value.elements[ 3 ]; - uniform.__data[ 5 ] = uniform.value.elements[ 4 ]; - uniform.__data[ 6 ] = uniform.value.elements[ 5 ]; - uniform.__data[ 7 ] = uniform.value.elements[ 0 ]; - uniform.__data[ 8 ] = uniform.value.elements[ 6 ]; - uniform.__data[ 9 ] = uniform.value.elements[ 7 ]; - uniform.__data[ 10 ] = uniform.value.elements[ 8 ]; - uniform.__data[ 11 ] = uniform.value.elements[ 0 ]; + const info = getUniformSize( value ); - } else { + // TODO add integer and struct support + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + uniform.__data[ 0 ] = value; + gl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data ); + + } else if ( value.isMatrix3 ) { + + // manually converting 3x3 to 3x4 - value.toArray( uniform.__data ); + 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; + + } } - gl.bufferSubData( 35345, offset, uniform.__data ); + gl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data ); } @@ -26238,25 +27663,26 @@ } - gl.bindBuffer( 35345, null ); + gl.bindBuffer( gl.UNIFORM_BUFFER, null ); } - function hasUniformChanged( uniform, index, cache ) { + function hasUniformChanged( uniform, index, indexArray, cache ) { const value = uniform.value; + const indexString = index + '_' + indexArray; - if ( cache[ index ] === undefined ) { + if ( cache[ indexString ] === undefined ) { // cache entry does not exist so far - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - cache[ index ] = value; + cache[ indexString ] = value; } else { - cache[ index ] = value.clone(); + cache[ indexString ] = value.clone(); } @@ -26264,21 +27690,21 @@ } else { + const cachedObject = cache[ indexString ]; + // compare current value with cached entry - if ( typeof value === 'number' ) { + if ( typeof value === 'number' || typeof value === 'boolean' ) { - if ( cache[ index ] !== value ) { + if ( cachedObject !== value ) { - cache[ index ] = value; + cache[ indexString ] = value; return true; } } else { - const cachedObject = cache[ index ]; - if ( cachedObject.equals( value ) === false ) { cachedObject.copy( value ); @@ -26303,46 +27729,53 @@ let offset = 0; // global buffer offset in bytes const chunkSize = 16; // size of a chunk in bytes - let chunkOffset = 0; // offset within a single chunk in bytes for ( let i = 0, l = uniforms.length; i < l; i ++ ) { - const uniform = uniforms[ i ]; - const info = getUniformSize( uniform ); + const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]; - // the following two properties will be used for partial buffer updates + for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) { - uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); - uniform.__offset = offset; + const uniform = uniformArray[ j ]; - // + const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]; + + for ( let k = 0, kl = values.length; k < kl; k ++ ) { - if ( i > 0 ) { + const value = values[ k ]; - chunkOffset = offset % chunkSize; + const info = getUniformSize( value ); - const remainingSizeInChunk = chunkSize - chunkOffset; + // Calculate the chunk offset + const chunkOffsetUniform = offset % chunkSize; - // check for chunk overflow + // Check for chunk overflow + if ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) { - if ( chunkOffset !== 0 && ( remainingSizeInChunk - info.boundary ) < 0 ) { + // Add padding and adjust offset + offset += ( chunkSize - chunkOffsetUniform ); + + } - // add padding and adjust offset + // the following two properties will be used for partial buffer updates - offset += ( chunkSize - chunkOffset ); + uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT ); uniform.__offset = offset; + + // Update the global offset + offset += info.storage; + + } } - offset += info.storage; - } // ensure correct final padding - chunkOffset = offset % chunkSize; + const chunkOffset = offset % chunkSize; if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset ); @@ -26355,1253 +27788,1600 @@ } - function getUniformSize( uniform ) { - - const value = uniform.value; + function getUniformSize( value ) { const info = { boundary: 0, // bytes storage: 0 // bytes }; - // determine sizes according to STD140 + // determine sizes according to STD140 + + if ( typeof value === 'number' || typeof value === 'boolean' ) { + + // float/int/bool + + info.boundary = 4; + info.storage = 4; + + } else if ( value.isVector2 ) { + + // vec2 + + info.boundary = 8; + info.storage = 8; + + } else if ( value.isVector3 || value.isColor ) { + + // 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 ) { + + // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + + info.boundary = 48; + info.storage = 48; + + } else if ( value.isMatrix4 ) { + + // mat4 + + info.boundary = 64; + info.storage = 64; + + } else if ( value.isTexture ) { + + console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + + } else { + + console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + + } + + return info; + + } + + function onUniformsGroupsDispose( event ) { + + const uniformsGroup = event.target; + + uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + + const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); + allocatedBindingPoints.splice( index, 1 ); + + gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + + delete buffers[ uniformsGroup.id ]; + delete updateList[ uniformsGroup.id ]; + + } + + function dispose() { + + for ( const id in buffers ) { + + 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 = true, + alpha = false, + antialias = false, + premultipliedAlpha = true, + preserveDrawingBuffer = false, + powerPreference = 'default', + failIfMajorPerformanceCaveat = false, + } = parameters; + + this.isWebGLRenderer = true; + + let _alpha; + + if ( context !== null ) { + + _alpha = context.getContextAttributes().alpha; + + } else { + + _alpha = alpha; + + } + + const uintClearColor = new Uint32Array( 4 ); + const intClearColor = new Int32Array( 4 ); + + let currentRenderList = null; + let currentRenderState = null; + + // render() can be called from within a callback triggered by another render. + // We track this so that the nested render call gets its list and state isolated from the parent render call. + + const renderListStack = []; + const renderStateStack = []; + + // public properties + + this.domElement = canvas; + + // Debug configuration container + this.debug = { + + /** + * 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; + + // physically based shading + + this._outputColorSpace = SRGBColorSpace; + + // physical lights + + this._useLegacyLights = false; + + // tone mapping + + this.toneMapping = NoToneMapping; + this.toneMappingExposure = 1.0; + + // internal properties + + const _this = this; + + let _isContextLost = false; + + // internal state cache + + let _currentActiveCubeFace = 0; + let _currentActiveMipmapLevel = 0; + let _currentRenderTarget = null; + let _currentMaterialId = - 1; + + let _currentCamera = null; + + const _currentViewport = new Vector4(); + const _currentScissor = new Vector4(); + let _currentScissorTest = null; + + const _currentClearColor = new Color( 0x000000 ); + let _currentClearAlpha = 0; + + // + + let _width = canvas.width; + let _height = canvas.height; + + let _pixelRatio = 1; + let _opaqueSort = null; + let _transparentSort = null; + + const _viewport = new Vector4( 0, 0, _width, _height ); + const _scissor = new Vector4( 0, 0, _width, _height ); + let _scissorTest = false; + + // frustum + + const _frustum = new Frustum(); + + // clipping + + let _clippingEnabled = false; + let _localClippingEnabled = false; + + // transmission + + let _transmissionRenderTarget = null; + + // camera matrices cache + + const _projScreenMatrix = new Matrix4(); + + const _vector2 = new Vector2(); + const _vector3 = new Vector3(); + + const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + + function getTargetPixelRatio() { + + return _currentRenderTarget === null ? _pixelRatio : 1; + + } + + // initialize + + let _gl = context; + + function getContext( contextNames, contextAttributes ) { + + for ( let i = 0; i < contextNames.length; i ++ ) { + + const contextName = contextNames[ i ]; + const context = canvas.getContext( contextName, contextAttributes ); + if ( context !== null ) return context; + + } + + return null; + + } + + try { + + const contextAttributes = { + alpha: true, + depth, + stencil, + antialias, + premultipliedAlpha, + preserveDrawingBuffer, + powerPreference, + failIfMajorPerformanceCaveat, + }; + + // OffscreenCanvas does not have setAttribute, see #22811 + if ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + + // event listeners must be registered before WebGL context is created, see #12753 + canvas.addEventListener( 'webglcontextlost', onContextLost, false ); + canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + + if ( _gl === null ) { + + const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + + if ( _this.isWebGL1Renderer === true ) { + + contextNames.shift(); + + } + + _gl = getContext( contextNames, contextAttributes ); + + if ( _gl === null ) { + + if ( getContext( contextNames ) ) { + + throw new Error( 'Error creating WebGL context with your selected attributes.' ); + + } else { + + throw new Error( 'Error creating WebGL context.' ); + + } + + } + + } + + if ( typeof WebGLRenderingContext !== 'undefined' && _gl instanceof WebGLRenderingContext ) { // @deprecated, r153 + + console.warn( 'THREE.WebGLRenderer: WebGL 1 support was deprecated in r153 and will be removed in r163.' ); + + } + + // Some experimental-webgl implementations do not have getShaderPrecisionFormat + + if ( _gl.getShaderPrecisionFormat === undefined ) { + + _gl.getShaderPrecisionFormat = function () { + + return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + + }; + + } + + } catch ( error ) { - if ( typeof value === 'number' ) { + console.error( 'THREE.WebGLRenderer: ' + error.message ); + throw error; - // float/int + } - info.boundary = 4; - info.storage = 4; + let extensions, capabilities, state, info; + let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; + let programCache, materials, renderLists, renderStates, clipping, shadowMap; - } else if ( value.isVector2 ) { + let background, morphtargets, bufferRenderer, indexedBufferRenderer; - // vec2 + let utils, bindingStates, uniformsGroups; - info.boundary = 8; - info.storage = 8; + function initGLContext() { - } else if ( value.isVector3 || value.isColor ) { + extensions = new WebGLExtensions( _gl ); - // vec3 + capabilities = new WebGLCapabilities( _gl, extensions, parameters ); - info.boundary = 16; - info.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes + extensions.init( capabilities ); - } else if ( value.isVector4 ) { + utils = new WebGLUtils( _gl, extensions, capabilities ); - // vec4 + state = new WebGLState( _gl, extensions, capabilities ); - info.boundary = 16; - info.storage = 16; + info = new WebGLInfo( _gl ); + properties = new WebGLProperties(); + textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); + cubemaps = new WebGLCubeMaps( _this ); + cubeuvmaps = new WebGLCubeUVMaps( _this ); + attributes = new WebGLAttributes( _gl, capabilities ); + bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); + geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); + objects = new WebGLObjects( _gl, geometries, attributes, info ); + morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); + clipping = new WebGLClipping( properties ); + programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); + materials = new WebGLMaterials( _this, properties ); + renderLists = new WebGLRenderLists(); + renderStates = new WebGLRenderStates( extensions, capabilities ); + background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha ); + shadowMap = new WebGLShadowMap( _this, objects, capabilities ); + uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); - } else if ( value.isMatrix3 ) { + bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); + indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); - // mat3 (in STD140 a 3x3 matrix is represented as 3x4) + info.programs = programCache.programs; - info.boundary = 48; - info.storage = 48; + _this.capabilities = capabilities; + _this.extensions = extensions; + _this.properties = properties; + _this.renderLists = renderLists; + _this.shadowMap = shadowMap; + _this.state = state; + _this.info = info; - } else if ( value.isMatrix4 ) { + } - // mat4 + initGLContext(); - info.boundary = 64; - info.storage = 64; + // xr - } else if ( value.isTexture ) { + const xr = new WebXRManager( _this, _gl ); - console.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' ); + this.xr = xr; - } else { + // API - console.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value ); + this.getContext = function () { - } + return _gl; - return info; + }; - } + this.getContextAttributes = function () { - function onUniformsGroupsDispose( event ) { + return _gl.getContextAttributes(); - const uniformsGroup = event.target; + }; - uniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose ); + this.forceContextLoss = function () { - const index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex ); - allocatedBindingPoints.splice( index, 1 ); + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.loseContext(); - gl.deleteBuffer( buffers[ uniformsGroup.id ] ); + }; - delete buffers[ uniformsGroup.id ]; - delete updateList[ uniformsGroup.id ]; + this.forceContextRestore = function () { - } + const extension = extensions.get( 'WEBGL_lose_context' ); + if ( extension ) extension.restoreContext(); - function dispose() { + }; - for ( const id in buffers ) { + this.getPixelRatio = function () { - gl.deleteBuffer( buffers[ id ] ); + return _pixelRatio; - } + }; - allocatedBindingPoints = []; - buffers = {}; - updateList = {}; + this.setPixelRatio = function ( value ) { - } + if ( value === undefined ) return; - return { + _pixelRatio = value; - bind: bind, - update: update, + this.setSize( _width, _height, false ); - dispose: dispose + }; - }; + this.getSize = function ( target ) { - } + return target.set( _width, _height ); - function createCanvasElement() { + }; - const canvas = createElementNS( 'canvas' ); - canvas.style.display = 'block'; - return canvas; + this.setSize = function ( width, height, updateStyle = true ) { - } + if ( xr.isPresenting ) { - function WebGLRenderer( parameters = {} ) { + console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); + return; - this.isWebGLRenderer = true; + } - const _canvas = parameters.canvas !== undefined ? parameters.canvas : createCanvasElement(), - _context = parameters.context !== undefined ? parameters.context : null, + _width = width; + _height = height; - _depth = parameters.depth !== undefined ? parameters.depth : true, - _stencil = parameters.stencil !== undefined ? parameters.stencil : true, - _antialias = parameters.antialias !== undefined ? parameters.antialias : false, - _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, - _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, - _powerPreference = parameters.powerPreference !== undefined ? parameters.powerPreference : 'default', - _failIfMajorPerformanceCaveat = parameters.failIfMajorPerformanceCaveat !== undefined ? parameters.failIfMajorPerformanceCaveat : false; + canvas.width = Math.floor( width * _pixelRatio ); + canvas.height = Math.floor( height * _pixelRatio ); - let _alpha; + if ( updateStyle === true ) { - if ( _context !== null ) { + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; - _alpha = _context.getContextAttributes().alpha; + } - } else { + this.setViewport( 0, 0, width, height ); - _alpha = parameters.alpha !== undefined ? parameters.alpha : false; + }; - } + this.getDrawingBufferSize = function ( target ) { - let currentRenderList = null; - let currentRenderState = null; + return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); - // render() can be called from within a callback triggered by another render. - // We track this so that the nested render call gets its list and state isolated from the parent render call. + }; - const renderListStack = []; - const renderStateStack = []; + this.setDrawingBufferSize = function ( width, height, pixelRatio ) { - // public properties + _width = width; + _height = height; - this.domElement = _canvas; + _pixelRatio = pixelRatio; - // Debug configuration container - this.debug = { + canvas.width = Math.floor( width * pixelRatio ); + canvas.height = Math.floor( height * pixelRatio ); - /** - * Enables error checking and reporting when shader programs are being compiled - * @type {boolean} - */ - checkShaderErrors: true - }; + this.setViewport( 0, 0, width, height ); - // clearing + }; - this.autoClear = true; - this.autoClearColor = true; - this.autoClearDepth = true; - this.autoClearStencil = true; + this.getCurrentViewport = function ( target ) { - // scene graph + return target.copy( _currentViewport ); - this.sortObjects = true; + }; - // user-defined clipping + this.getViewport = function ( target ) { - this.clippingPlanes = []; - this.localClippingEnabled = false; + return target.copy( _viewport ); - // physically based shading + }; - this.outputEncoding = LinearEncoding; + this.setViewport = function ( x, y, width, height ) { - // physical lights + if ( x.isVector4 ) { - this.physicallyCorrectLights = false; + _viewport.set( x.x, x.y, x.z, x.w ); - // tone mapping + } else { - this.toneMapping = NoToneMapping; - this.toneMappingExposure = 1.0; + _viewport.set( x, y, width, height ); - // internal properties + } - const _this = this; + state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); - let _isContextLost = false; + }; - // internal state cache + this.getScissor = function ( target ) { - let _currentActiveCubeFace = 0; - let _currentActiveMipmapLevel = 0; - let _currentRenderTarget = null; - let _currentMaterialId = - 1; + return target.copy( _scissor ); - let _currentCamera = null; + }; - const _currentViewport = new Vector4(); - const _currentScissor = new Vector4(); - let _currentScissorTest = null; + this.setScissor = function ( x, y, width, height ) { - // + if ( x.isVector4 ) { - let _width = _canvas.width; - let _height = _canvas.height; + _scissor.set( x.x, x.y, x.z, x.w ); - let _pixelRatio = 1; - let _opaqueSort = null; - let _transparentSort = null; + } else { - const _viewport = new Vector4( 0, 0, _width, _height ); - const _scissor = new Vector4( 0, 0, _width, _height ); - let _scissorTest = false; + _scissor.set( x, y, width, height ); - // frustum + } - const _frustum = new Frustum(); + state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); - // clipping + }; - let _clippingEnabled = false; - let _localClippingEnabled = false; + this.getScissorTest = function () { - // transmission + return _scissorTest; - let _transmissionRenderTarget = null; + }; - // camera matrices cache + this.setScissorTest = function ( boolean ) { - const _projScreenMatrix = new Matrix4(); + state.setScissorTest( _scissorTest = boolean ); - const _vector2 = new Vector2(); - const _vector3 = new Vector3(); + }; - const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true }; + this.setOpaqueSort = function ( method ) { - function getTargetPixelRatio() { + _opaqueSort = method; - return _currentRenderTarget === null ? _pixelRatio : 1; + }; - } + this.setTransparentSort = function ( method ) { - // initialize + _transparentSort = method; - let _gl = _context; + }; - function getContext( contextNames, contextAttributes ) { + // Clearing - for ( let i = 0; i < contextNames.length; i ++ ) { + this.getClearColor = function ( target ) { - const contextName = contextNames[ i ]; - const context = _canvas.getContext( contextName, contextAttributes ); - if ( context !== null ) return context; + return target.copy( background.getClearColor() ); - } + }; - return null; + this.setClearColor = function () { - } + background.setClearColor.apply( background, arguments ); - try { + }; + + this.getClearAlpha = function () { + + return background.getClearAlpha(); - const contextAttributes = { - alpha: true, - depth: _depth, - stencil: _stencil, - antialias: _antialias, - premultipliedAlpha: _premultipliedAlpha, - preserveDrawingBuffer: _preserveDrawingBuffer, - powerPreference: _powerPreference, - failIfMajorPerformanceCaveat: _failIfMajorPerformanceCaveat }; - // OffscreenCanvas does not have setAttribute, see #22811 - if ( 'setAttribute' in _canvas ) _canvas.setAttribute( 'data-engine', `three.js r${REVISION}` ); + this.setClearAlpha = function () { - // event listeners must be registered before WebGL context is created, see #12753 - _canvas.addEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.addEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + background.setClearAlpha.apply( background, arguments ); - if ( _gl === null ) { + }; - const contextNames = [ 'webgl2', 'webgl', 'experimental-webgl' ]; + this.clear = function ( color = true, depth = true, stencil = true ) { - if ( _this.isWebGL1Renderer === true ) { + let bits = 0; - contextNames.shift(); + if ( color ) { - } + // check if we're trying to clear an integer target + let isIntegerFormat = false; + if ( _currentRenderTarget !== null ) { - _gl = getContext( contextNames, contextAttributes ); + const targetFormat = _currentRenderTarget.texture.format; + isIntegerFormat = targetFormat === RGBAIntegerFormat || + targetFormat === RGIntegerFormat || + targetFormat === RedIntegerFormat; - if ( _gl === null ) { + } - if ( getContext( contextNames ) ) { + // use the appropriate clear functions to clear the target if it's a signed + // or unsigned integer target + if ( isIntegerFormat ) { - throw new Error( 'Error creating WebGL context with your selected attributes.' ); + const targetType = _currentRenderTarget.texture.type; + const isUnsignedType = targetType === UnsignedByteType || + targetType === UnsignedIntType || + targetType === UnsignedShortType || + targetType === UnsignedInt248Type || + targetType === UnsignedShort4444Type || + targetType === UnsignedShort5551Type; - } else { + const clearColor = background.getClearColor(); + const a = background.getClearAlpha(); + const r = clearColor.r; + const g = clearColor.g; + const b = clearColor.b; - throw new Error( 'Error creating WebGL context.' ); + 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 ); + + } - // Some experimental-webgl implementations do not have getShaderPrecisionFormat + } else { - if ( _gl.getShaderPrecisionFormat === undefined ) { + bits |= _gl.COLOR_BUFFER_BIT; - _gl.getShaderPrecisionFormat = function () { + } - return { 'rangeMin': 1, 'rangeMax': 1, 'precision': 1 }; + } - }; + if ( depth ) bits |= _gl.DEPTH_BUFFER_BIT; + if ( stencil ) { - } + bits |= _gl.STENCIL_BUFFER_BIT; + this.state.buffers.stencil.setMask( 0xffffffff ); - } catch ( error ) { + } - console.error( 'THREE.WebGLRenderer: ' + error.message ); - throw error; + _gl.clear( bits ); - } + }; - let extensions, capabilities, state, info; - let properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects; - let programCache, materials, renderLists, renderStates, clipping, shadowMap; + this.clearColor = function () { - let background, morphtargets, bufferRenderer, indexedBufferRenderer; + this.clear( true, false, false ); - let utils, bindingStates, uniformsGroups; + }; - function initGLContext() { + this.clearDepth = function () { - extensions = new WebGLExtensions( _gl ); + this.clear( false, true, false ); - capabilities = new WebGLCapabilities( _gl, extensions, parameters ); + }; - extensions.init( capabilities ); + this.clearStencil = function () { - utils = new WebGLUtils( _gl, extensions, capabilities ); + this.clear( false, false, true ); - state = new WebGLState( _gl, extensions, capabilities ); + }; - info = new WebGLInfo(); - properties = new WebGLProperties(); - textures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ); - cubemaps = new WebGLCubeMaps( _this ); - cubeuvmaps = new WebGLCubeUVMaps( _this ); - attributes = new WebGLAttributes( _gl, capabilities ); - bindingStates = new WebGLBindingStates( _gl, extensions, attributes, capabilities ); - geometries = new WebGLGeometries( _gl, attributes, info, bindingStates ); - objects = new WebGLObjects( _gl, geometries, attributes, info ); - morphtargets = new WebGLMorphtargets( _gl, capabilities, textures ); - clipping = new WebGLClipping( properties ); - programCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ); - materials = new WebGLMaterials( _this, properties ); - renderLists = new WebGLRenderLists(); - renderStates = new WebGLRenderStates( extensions, capabilities ); - background = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, _premultipliedAlpha ); - shadowMap = new WebGLShadowMap( _this, objects, capabilities ); - uniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state ); + // - bufferRenderer = new WebGLBufferRenderer( _gl, extensions, info, capabilities ); - indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info, capabilities ); + this.dispose = function () { - info.programs = programCache.programs; + canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); + canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); + canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); - _this.capabilities = capabilities; - _this.extensions = extensions; - _this.properties = properties; - _this.renderLists = renderLists; - _this.shadowMap = shadowMap; - _this.state = state; - _this.info = info; + renderLists.dispose(); + renderStates.dispose(); + properties.dispose(); + cubemaps.dispose(); + cubeuvmaps.dispose(); + objects.dispose(); + bindingStates.dispose(); + uniformsGroups.dispose(); + programCache.dispose(); - } + xr.dispose(); - initGLContext(); + xr.removeEventListener( 'sessionstart', onXRSessionStart ); + xr.removeEventListener( 'sessionend', onXRSessionEnd ); - // xr + if ( _transmissionRenderTarget ) { - const xr = new WebXRManager( _this, _gl ); + _transmissionRenderTarget.dispose(); + _transmissionRenderTarget = null; - this.xr = xr; + } - // API + animation.stop(); - this.getContext = function () { + }; - return _gl; + // Events - }; + function onContextLost( event ) { - this.getContextAttributes = function () { + event.preventDefault(); - return _gl.getContextAttributes(); + console.log( 'THREE.WebGLRenderer: Context Lost.' ); - }; + _isContextLost = true; - this.forceContextLoss = function () { + } - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.loseContext(); + function onContextRestore( /* event */ ) { - }; + console.log( 'THREE.WebGLRenderer: Context Restored.' ); - this.forceContextRestore = function () { + _isContextLost = false; - const extension = extensions.get( 'WEBGL_lose_context' ); - if ( extension ) extension.restoreContext(); + const infoAutoReset = info.autoReset; + const shadowMapEnabled = shadowMap.enabled; + const shadowMapAutoUpdate = shadowMap.autoUpdate; + const shadowMapNeedsUpdate = shadowMap.needsUpdate; + const shadowMapType = shadowMap.type; - }; + initGLContext(); - this.getPixelRatio = function () { + info.autoReset = infoAutoReset; + shadowMap.enabled = shadowMapEnabled; + shadowMap.autoUpdate = shadowMapAutoUpdate; + shadowMap.needsUpdate = shadowMapNeedsUpdate; + shadowMap.type = shadowMapType; - return _pixelRatio; + } - }; + function onContextCreationError( event ) { - this.setPixelRatio = function ( value ) { + console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); - if ( value === undefined ) return; + } - _pixelRatio = value; + function onMaterialDispose( event ) { - this.setSize( _width, _height, false ); + const material = event.target; - }; + material.removeEventListener( 'dispose', onMaterialDispose ); - this.getSize = function ( target ) { + deallocateMaterial( material ); - return target.set( _width, _height ); + } - }; + // Buffer deallocation - this.setSize = function ( width, height, updateStyle ) { + function deallocateMaterial( material ) { - if ( xr.isPresenting ) { + releaseMaterialProgramReferences( material ); - console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' ); - return; + properties.remove( material ); } - _width = width; - _height = height; - _canvas.width = Math.floor( width * _pixelRatio ); - _canvas.height = Math.floor( height * _pixelRatio ); + function releaseMaterialProgramReferences( material ) { - if ( updateStyle !== false ) { + const programs = properties.get( material ).programs; - _canvas.style.width = width + 'px'; - _canvas.style.height = height + 'px'; + if ( programs !== undefined ) { - } + programs.forEach( function ( program ) { - this.setViewport( 0, 0, width, height ); + programCache.releaseProgram( program ); - }; + } ); - this.getDrawingBufferSize = function ( target ) { + if ( material.isShaderMaterial ) { - return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor(); + programCache.releaseShaderCache( material ); - }; + } - this.setDrawingBufferSize = function ( width, height, pixelRatio ) { + } - _width = width; - _height = height; + } - _pixelRatio = pixelRatio; + // Buffer rendering - _canvas.width = Math.floor( width * pixelRatio ); - _canvas.height = Math.floor( height * pixelRatio ); + this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { - this.setViewport( 0, 0, width, height ); + if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) - }; + const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); - this.getCurrentViewport = function ( target ) { + const program = setProgram( camera, scene, geometry, material, object ); - return target.copy( _currentViewport ); + state.setMaterial( material, frontFaceCW ); - }; + // - this.getViewport = function ( target ) { + let index = geometry.index; + let rangeFactor = 1; - return target.copy( _viewport ); + if ( material.wireframe === true ) { - }; + index = geometries.getWireframeAttribute( geometry ); - this.setViewport = function ( x, y, width, height ) { + if ( index === undefined ) return; - if ( x.isVector4 ) { + rangeFactor = 2; - _viewport.set( x.x, x.y, x.z, x.w ); + } - } else { + // - _viewport.set( x, y, width, height ); + const drawRange = geometry.drawRange; + const position = geometry.attributes.position; - } + let drawStart = drawRange.start * rangeFactor; + let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; - state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor() ); + if ( group !== null ) { - }; + drawStart = Math.max( drawStart, group.start * rangeFactor ); + drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); - this.getScissor = function ( target ) { + } - return target.copy( _scissor ); + if ( index !== null ) { - }; + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, index.count ); - this.setScissor = function ( x, y, width, height ) { + } else if ( position !== undefined && position !== null ) { - if ( x.isVector4 ) { + drawStart = Math.max( drawStart, 0 ); + drawEnd = Math.min( drawEnd, position.count ); - _scissor.set( x.x, x.y, x.z, x.w ); + } - } else { + const drawCount = drawEnd - drawStart; - _scissor.set( x, y, width, height ); + if ( drawCount < 0 || drawCount === Infinity ) return; - } + // - state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor() ); + bindingStates.setup( object, material, program, geometry, index ); - }; + let attribute; + let renderer = bufferRenderer; - this.getScissorTest = function () { + if ( index !== null ) { - return _scissorTest; + attribute = attributes.get( index ); - }; + renderer = indexedBufferRenderer; + renderer.setIndex( attribute ); - this.setScissorTest = function ( boolean ) { + } - state.setScissorTest( _scissorTest = boolean ); + // - }; + if ( object.isMesh ) { - this.setOpaqueSort = function ( method ) { + if ( material.wireframe === true ) { - _opaqueSort = method; + state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); + renderer.setMode( _gl.LINES ); - }; + } else { - this.setTransparentSort = function ( method ) { + renderer.setMode( _gl.TRIANGLES ); - _transparentSort = method; + } - }; + } else if ( object.isLine ) { - // Clearing + let lineWidth = material.linewidth; - this.getClearColor = function ( target ) { + if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material - return target.copy( background.getClearColor() ); + state.setLineWidth( lineWidth * getTargetPixelRatio() ); - }; + if ( object.isLineSegments ) { - this.setClearColor = function () { + renderer.setMode( _gl.LINES ); - background.setClearColor.apply( background, arguments ); + } else if ( object.isLineLoop ) { - }; + renderer.setMode( _gl.LINE_LOOP ); - this.getClearAlpha = function () { + } else { - return background.getClearAlpha(); + renderer.setMode( _gl.LINE_STRIP ); - }; + } - this.setClearAlpha = function () { + } else if ( object.isPoints ) { - background.setClearAlpha.apply( background, arguments ); + renderer.setMode( _gl.POINTS ); - }; + } else if ( object.isSprite ) { - this.clear = function ( color = true, depth = true, stencil = true ) { + renderer.setMode( _gl.TRIANGLES ); - let bits = 0; + } - if ( color ) bits |= 16384; - if ( depth ) bits |= 256; - if ( stencil ) bits |= 1024; + if ( object.isBatchedMesh ) { - _gl.clear( bits ); + renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount ); - }; + } else if ( object.isInstancedMesh ) { - this.clearColor = function () { + renderer.renderInstances( drawStart, drawCount, object.count ); - this.clear( true, false, false ); + } else if ( geometry.isInstancedBufferGeometry ) { - }; + const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; + const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); - this.clearDepth = function () { + renderer.renderInstances( drawStart, drawCount, instanceCount ); - this.clear( false, true, false ); + } else { - }; + renderer.render( drawStart, drawCount ); - this.clearStencil = function () { + } - this.clear( false, false, true ); + }; - }; + // Compile - // + function prepareMaterial( material, scene, object ) { - this.dispose = function () { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - _canvas.removeEventListener( 'webglcontextlost', onContextLost, false ); - _canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false ); - _canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false ); + material.side = BackSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - renderLists.dispose(); - renderStates.dispose(); - properties.dispose(); - cubemaps.dispose(); - cubeuvmaps.dispose(); - objects.dispose(); - bindingStates.dispose(); - uniformsGroups.dispose(); - programCache.dispose(); + material.side = FrontSide; + material.needsUpdate = true; + getProgram( material, scene, object ); - xr.dispose(); + material.side = DoubleSide; - xr.removeEventListener( 'sessionstart', onXRSessionStart ); - xr.removeEventListener( 'sessionend', onXRSessionEnd ); + } else { - if ( _transmissionRenderTarget ) { + getProgram( material, scene, object ); - _transmissionRenderTarget.dispose(); - _transmissionRenderTarget = null; + } } - animation.stop(); + this.compile = function ( scene, camera, targetScene = null ) { - }; + if ( targetScene === null ) targetScene = scene; - // Events + currentRenderState = renderStates.get( targetScene ); + currentRenderState.init(); - function onContextLost( event ) { + renderStateStack.push( currentRenderState ); - event.preventDefault(); + // gather lights from both the target scene and the new object that will be added to the scene. - console.log( 'THREE.WebGLRenderer: Context Lost.' ); + targetScene.traverseVisible( function ( object ) { - _isContextLost = true; + if ( object.isLight && object.layers.test( camera.layers ) ) { - } + currentRenderState.pushLight( object ); - function onContextRestore( /* event */ ) { + if ( object.castShadow ) { - console.log( 'THREE.WebGLRenderer: Context Restored.' ); + currentRenderState.pushShadow( object ); - _isContextLost = false; + } - const infoAutoReset = info.autoReset; - const shadowMapEnabled = shadowMap.enabled; - const shadowMapAutoUpdate = shadowMap.autoUpdate; - const shadowMapNeedsUpdate = shadowMap.needsUpdate; - const shadowMapType = shadowMap.type; + } - initGLContext(); + } ); - info.autoReset = infoAutoReset; - shadowMap.enabled = shadowMapEnabled; - shadowMap.autoUpdate = shadowMapAutoUpdate; - shadowMap.needsUpdate = shadowMapNeedsUpdate; - shadowMap.type = shadowMapType; + if ( scene !== targetScene ) { - } + scene.traverseVisible( function ( object ) { - function onContextCreationError( event ) { + if ( object.isLight && object.layers.test( camera.layers ) ) { - console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage ); + currentRenderState.pushLight( object ); - } + if ( object.castShadow ) { - function onMaterialDispose( event ) { + currentRenderState.pushShadow( object ); - const material = event.target; + } - material.removeEventListener( 'dispose', onMaterialDispose ); + } - deallocateMaterial( material ); + } ); - } + } - // Buffer deallocation + currentRenderState.setupLights( _this._useLegacyLights ); - function deallocateMaterial( material ) { + // Only initialize materials in the new scene, not the targetScene. - releaseMaterialProgramReferences( material ); + const materials = new Set(); - properties.remove( material ); + scene.traverse( function ( object ) { - } + const material = object.material; + if ( material ) { - function releaseMaterialProgramReferences( material ) { + if ( Array.isArray( material ) ) { - const programs = properties.get( material ).programs; + for ( let i = 0; i < material.length; i ++ ) { - if ( programs !== undefined ) { + const material2 = material[ i ]; - programs.forEach( function ( program ) { + prepareMaterial( material2, targetScene, object ); + materials.add( material2 ); - programCache.releaseProgram( program ); + } - } ); + } else { - if ( material.isShaderMaterial ) { + prepareMaterial( material, targetScene, object ); + materials.add( material ); - programCache.releaseShaderCache( material ); + } - } + } - } + } ); - } + renderStateStack.pop(); + currentRenderState = null; - // Buffer rendering + return materials; - this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) { + }; - if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null) + // compileAsync - const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 ); + this.compileAsync = function ( scene, camera, targetScene = null ) { - const program = setProgram( camera, scene, geometry, material, object ); + const materials = this.compile( scene, camera, targetScene ); - state.setMaterial( material, frontFaceCW ); + // Wait for all the materials in the new object to indicate that they're + // ready to be used before resolving the promise. - // + return new Promise( ( resolve ) => { - let index = geometry.index; - let rangeFactor = 1; + function checkMaterialsReady() { - if ( material.wireframe === true ) { + materials.forEach( function ( material ) { - index = geometries.getWireframeAttribute( geometry ); - rangeFactor = 2; + const materialProperties = properties.get( material ); + const program = materialProperties.currentProgram; - } + if ( program.isReady() ) { - // + // remove any programs that report they're ready to use from the list + materials.delete( material ); - const drawRange = geometry.drawRange; - const position = geometry.attributes.position; + } + + } ); - let drawStart = drawRange.start * rangeFactor; - let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor; + // once the list of compiling materials is empty, call the callback - if ( group !== null ) { + if ( materials.size === 0 ) { - drawStart = Math.max( drawStart, group.start * rangeFactor ); - drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor ); + resolve( scene ); + return; - } + } - if ( index !== null ) { + // if some materials are still not ready, wait a bit and check again - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, index.count ); + setTimeout( checkMaterialsReady, 10 ); - } else if ( position !== undefined && position !== null ) { + } - drawStart = Math.max( drawStart, 0 ); - drawEnd = Math.min( drawEnd, position.count ); + if ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) { - } + // If we can check the compilation status of the materials without + // blocking then do so right away. - const drawCount = drawEnd - drawStart; + checkMaterialsReady(); - if ( drawCount < 0 || drawCount === Infinity ) return; + } else { - // + // Otherwise start by waiting a bit to give the materials we just + // initialized a chance to finish. - bindingStates.setup( object, material, program, geometry, index ); + setTimeout( checkMaterialsReady, 10 ); - let attribute; - let renderer = bufferRenderer; + } - if ( index !== null ) { + } ); - attribute = attributes.get( index ); + }; - renderer = indexedBufferRenderer; - renderer.setIndex( attribute ); + // Animation Loop - } + let onAnimationFrameCallback = null; - // + function onAnimationFrame( time ) { - if ( object.isMesh ) { + if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); - if ( material.wireframe === true ) { + } - state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() ); - renderer.setMode( 1 ); + function onXRSessionStart() { - } else { + animation.stop(); - renderer.setMode( 4 ); + } - } + function onXRSessionEnd() { - } else if ( object.isLine ) { + animation.start(); - let lineWidth = material.linewidth; + } - if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material + const animation = new WebGLAnimation(); + animation.setAnimationLoop( onAnimationFrame ); - state.setLineWidth( lineWidth * getTargetPixelRatio() ); + if ( typeof self !== 'undefined' ) animation.setContext( self ); - if ( object.isLineSegments ) { + this.setAnimationLoop = function ( callback ) { - renderer.setMode( 1 ); + onAnimationFrameCallback = callback; + xr.setAnimationLoop( callback ); - } else if ( object.isLineLoop ) { + ( callback === null ) ? animation.stop() : animation.start(); - renderer.setMode( 2 ); + }; - } else { + xr.addEventListener( 'sessionstart', onXRSessionStart ); + xr.addEventListener( 'sessionend', onXRSessionEnd ); - renderer.setMode( 3 ); + // Rendering - } + this.render = function ( scene, camera ) { - } else if ( object.isPoints ) { + if ( camera !== undefined && camera.isCamera !== true ) { - renderer.setMode( 0 ); + console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); + return; - } else if ( object.isSprite ) { + } - renderer.setMode( 4 ); + if ( _isContextLost === true ) return; - } + // update scene graph - if ( object.isInstancedMesh ) { + if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - renderer.renderInstances( drawStart, drawCount, object.count ); + // update camera matrices and frustum - } else if ( geometry.isInstancedBufferGeometry ) { + if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); - const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity; - const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount ); + if ( xr.enabled === true && xr.isPresenting === true ) { - renderer.renderInstances( drawStart, drawCount, instanceCount ); + if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); - } else { + camera = xr.getCamera(); // use XR camera for rendering - renderer.render( drawStart, drawCount ); + } - } + // + if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); - }; + currentRenderState = renderStates.get( scene, renderStateStack.length ); + currentRenderState.init(); - // Compile + renderStateStack.push( currentRenderState ); - this.compile = function ( scene, camera ) { + _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); + _frustum.setFromProjectionMatrix( _projScreenMatrix ); - function prepare( material, scene, object ) { + _localClippingEnabled = this.localClippingEnabled; + _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled ); - if ( material.transparent === true && material.side === DoubleSide ) { + currentRenderList = renderLists.get( scene, renderListStack.length ); + currentRenderList.init(); - material.side = BackSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + renderListStack.push( currentRenderList ); - material.side = FrontSide; - material.needsUpdate = true; - getProgram( material, scene, object ); + projectObject( scene, camera, 0, _this.sortObjects ); - material.side = DoubleSide; + currentRenderList.finish(); - } else { + if ( _this.sortObjects === true ) { - getProgram( material, scene, object ); + currentRenderList.sort( _opaqueSort, _transparentSort ); } - } + // - currentRenderState = renderStates.get( scene ); - currentRenderState.init(); + this.info.render.frame ++; - renderStateStack.push( currentRenderState ); + if ( _clippingEnabled === true ) clipping.beginShadows(); - scene.traverseVisible( function ( object ) { + const shadowsArray = currentRenderState.state.shadowsArray; - if ( object.isLight && object.layers.test( camera.layers ) ) { + shadowMap.render( shadowsArray, scene, camera ); - currentRenderState.pushLight( object ); + if ( _clippingEnabled === true ) clipping.endShadows(); - if ( object.castShadow ) { + // - currentRenderState.pushShadow( object ); + if ( this.info.autoReset === true ) this.info.reset(); - } - } + // - } ); + background.render( currentRenderList, scene ); - currentRenderState.setupLights( _this.physicallyCorrectLights ); + // render scene - scene.traverse( function ( object ) { + currentRenderState.setupLights( _this._useLegacyLights ); - const material = object.material; + if ( camera.isArrayCamera ) { - if ( material ) { + const cameras = camera.cameras; - if ( Array.isArray( material ) ) { + for ( let i = 0, l = cameras.length; i < l; i ++ ) { - for ( let i = 0; i < material.length; i ++ ) { + const camera2 = cameras[ i ]; - const material2 = material[ i ]; + renderScene( currentRenderList, scene, camera2, camera2.viewport ); - prepare( material2, scene, object ); + } - } + } else { - } else { + renderScene( currentRenderList, scene, camera ); - prepare( material, scene, object ); + } - } + // - } + if ( _currentRenderTarget !== null ) { - } ); + // resolve multisample renderbuffers to a single-sample texture if necessary - renderStateStack.pop(); - currentRenderState = null; + textures.updateMultisampleRenderTarget( _currentRenderTarget ); - }; + // Generate mipmap if we're using any kind of mipmap filtering - // Animation Loop + textures.updateRenderTargetMipmap( _currentRenderTarget ); - let onAnimationFrameCallback = null; + } - function onAnimationFrame( time ) { + // - if ( onAnimationFrameCallback ) onAnimationFrameCallback( time ); + if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); - } + // _gl.finish(); - function onXRSessionStart() { + bindingStates.resetDefaultState(); + _currentMaterialId = - 1; + _currentCamera = null; - animation.stop(); + renderStateStack.pop(); - } + if ( renderStateStack.length > 0 ) { - function onXRSessionEnd() { + currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; - animation.start(); + } else { - } + currentRenderState = null; - const animation = new WebGLAnimation(); - animation.setAnimationLoop( onAnimationFrame ); + } - if ( typeof self !== 'undefined' ) animation.setContext( self ); + renderListStack.pop(); - this.setAnimationLoop = function ( callback ) { + if ( renderListStack.length > 0 ) { - onAnimationFrameCallback = callback; - xr.setAnimationLoop( callback ); + currentRenderList = renderListStack[ renderListStack.length - 1 ]; - ( callback === null ) ? animation.stop() : animation.start(); + } else { - }; + currentRenderList = null; - xr.addEventListener( 'sessionstart', onXRSessionStart ); - xr.addEventListener( 'sessionend', onXRSessionEnd ); + } - // Rendering + }; - this.render = function ( scene, camera ) { + function projectObject( object, camera, groupOrder, sortObjects ) { - if ( camera !== undefined && camera.isCamera !== true ) { + if ( object.visible === false ) return; - console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); - return; + const visible = object.layers.test( camera.layers ); - } + if ( visible ) { - if ( _isContextLost === true ) return; + if ( object.isGroup ) { - // update scene graph + groupOrder = object.renderOrder; - if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); + } else if ( object.isLOD ) { - // update camera matrices and frustum + if ( object.autoUpdate === true ) object.update( camera ); - if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld(); + } else if ( object.isLight ) { - if ( xr.enabled === true && xr.isPresenting === true ) { + currentRenderState.pushLight( object ); - if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); + if ( object.castShadow ) { - camera = xr.getCamera(); // use XR camera for rendering + currentRenderState.pushShadow( object ); - } + } - // - if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget ); + } else if ( object.isSprite ) { - currentRenderState = renderStates.get( scene, renderStateStack.length ); - currentRenderState.init(); + if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { - renderStateStack.push( currentRenderState ); + if ( sortObjects ) { - _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); - _frustum.setFromProjectionMatrix( _projScreenMatrix ); + _vector3.setFromMatrixPosition( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - _localClippingEnabled = this.localClippingEnabled; - _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled, camera ); + } - currentRenderList = renderLists.get( scene, renderListStack.length ); - currentRenderList.init(); + const geometry = objects.update( object ); + const material = object.material; - renderListStack.push( currentRenderList ); + if ( material.visible ) { - projectObject( scene, camera, 0, _this.sortObjects ); + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - currentRenderList.finish(); + } - if ( _this.sortObjects === true ) { + } - currentRenderList.sort( _opaqueSort, _transparentSort ); + } else if ( object.isMesh || object.isLine || object.isPoints ) { - } + if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - // + const geometry = objects.update( object ); + const material = object.material; - if ( _clippingEnabled === true ) clipping.beginShadows(); + if ( sortObjects ) { - const shadowsArray = currentRenderState.state.shadowsArray; + if ( object.boundingSphere !== undefined ) { - shadowMap.render( shadowsArray, scene, camera ); + if ( object.boundingSphere === null ) object.computeBoundingSphere(); + _vector3.copy( object.boundingSphere.center ); - if ( _clippingEnabled === true ) clipping.endShadows(); + } else { - // + if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); + _vector3.copy( geometry.boundingSphere.center ); - if ( this.info.autoReset === true ) this.info.reset(); + } - // + _vector3 + .applyMatrix4( object.matrixWorld ) + .applyMatrix4( _projScreenMatrix ); - background.render( currentRenderList, scene ); + } - // render scene + if ( Array.isArray( material ) ) { - currentRenderState.setupLights( _this.physicallyCorrectLights ); + const groups = geometry.groups; - if ( camera.isArrayCamera ) { + for ( let i = 0, l = groups.length; i < l; i ++ ) { - const cameras = camera.cameras; + const group = groups[ i ]; + const groupMaterial = material[ group.materialIndex ]; - for ( let i = 0, l = cameras.length; i < l; i ++ ) { + if ( groupMaterial && groupMaterial.visible ) { - const camera2 = cameras[ i ]; + currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); - renderScene( currentRenderList, scene, camera2, camera2.viewport ); + } - } + } - } else { + } else if ( material.visible ) { - renderScene( currentRenderList, scene, camera ); + currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); - } + } - // + } - if ( _currentRenderTarget !== null ) { + } + + } - // resolve multisample renderbuffers to a single-sample texture if necessary + const children = object.children; - textures.updateMultisampleRenderTarget( _currentRenderTarget ); + for ( let i = 0, l = children.length; i < l; i ++ ) { - // Generate mipmap if we're using any kind of mipmap filtering + projectObject( children[ i ], camera, groupOrder, sortObjects ); - textures.updateRenderTargetMipmap( _currentRenderTarget ); + } } - // + function renderScene( currentRenderList, scene, camera, viewport ) { - if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera ); + const opaqueObjects = currentRenderList.opaque; + const transmissiveObjects = currentRenderList.transmissive; + const transparentObjects = currentRenderList.transparent; - // _gl.finish(); + currentRenderState.setupLightsView( camera ); - bindingStates.resetDefaultState(); - _currentMaterialId = - 1; - _currentCamera = null; + if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera ); - renderStateStack.pop(); + if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ); - if ( renderStateStack.length > 0 ) { + if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); - currentRenderState = renderStateStack[ renderStateStack.length - 1 ]; + if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); + if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); + if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); - } else { + // Ensure depth buffer writing is enabled so it can be cleared on next render - currentRenderState = null; + state.buffers.depth.setTest( true ); + state.buffers.depth.setMask( true ); + state.buffers.color.setMask( true ); - } + state.setPolygonOffset( false ); - renderListStack.pop(); + } - if ( renderListStack.length > 0 ) { + function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) { - currentRenderList = renderListStack[ renderListStack.length - 1 ]; + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } else { + if ( overrideMaterial !== null ) { - currentRenderList = null; + return; - } + } - }; + const isWebGL2 = capabilities.isWebGL2; - function projectObject( object, camera, groupOrder, sortObjects ) { + if ( _transmissionRenderTarget === null ) { - if ( object.visible === false ) return; + _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { + generateMipmaps: true, + type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, + minFilter: LinearMipmapLinearFilter, + samples: ( isWebGL2 ) ? 4 : 0 + } ); - const visible = object.layers.test( camera.layers ); + // debug - if ( visible ) { + /* + const geometry = new PlaneGeometry(); + const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } ); - if ( object.isGroup ) { + const mesh = new Mesh( geometry, material ); + scene.add( mesh ); + */ - groupOrder = object.renderOrder; + } - } else if ( object.isLOD ) { + _this.getDrawingBufferSize( _vector2 ); - if ( object.autoUpdate === true ) object.update( camera ); + if ( isWebGL2 ) { - } else if ( object.isLight ) { + _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); - currentRenderState.pushLight( object ); + } else { - if ( object.castShadow ) { + _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); - currentRenderState.pushShadow( object ); + } - } + // - } else if ( object.isSprite ) { + const currentRenderTarget = _this.getRenderTarget(); + _this.setRenderTarget( _transmissionRenderTarget ); - if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) { + _this.getClearColor( _currentClearColor ); + _currentClearAlpha = _this.getClearAlpha(); + if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 ); - if ( sortObjects ) { + _this.clear(); - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + // 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; - } + renderObjects( opaqueObjects, scene, camera ); - const geometry = objects.update( object ); - const material = object.material; + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - if ( material.visible ) { + let renderTargetNeedsUpdate = false; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + for ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) { - } + const renderItem = transmissiveObjects[ i ]; - } + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = renderItem.material; + const group = renderItem.group; - } else if ( object.isMesh || object.isLine || object.isPoints ) { + if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) { - if ( object.isSkinnedMesh ) { + const currentSide = material.side; - // update skeleton only once in a frame + material.side = BackSide; + material.needsUpdate = true; - if ( object.skeleton.frame !== info.render.frame ) { + renderObject( object, scene, camera, geometry, material, group ); - object.skeleton.update(); - object.skeleton.frame = info.render.frame; + material.side = currentSide; + material.needsUpdate = true; - } + renderTargetNeedsUpdate = true; } - if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) { - - if ( sortObjects ) { + } - _vector3.setFromMatrixPosition( object.matrixWorld ) - .applyMatrix4( _projScreenMatrix ); + if ( renderTargetNeedsUpdate === true ) { - } + textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); + textures.updateRenderTargetMipmap( _transmissionRenderTarget ); - const geometry = objects.update( object ); - const material = object.material; + } - if ( Array.isArray( material ) ) { + _this.setRenderTarget( currentRenderTarget ); - const groups = geometry.groups; + _this.setClearColor( _currentClearColor, _currentClearAlpha ); - for ( let i = 0, l = groups.length; i < l; i ++ ) { + _this.toneMapping = currentToneMapping; - const group = groups[ i ]; - const groupMaterial = material[ group.materialIndex ]; + } - if ( groupMaterial && groupMaterial.visible ) { + function renderObjects( renderList, scene, camera ) { - currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector3.z, group ); + const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; - } + for ( let i = 0, l = renderList.length; i < l; i ++ ) { - } + const renderItem = renderList[ i ]; - } else if ( material.visible ) { + const object = renderItem.object; + const geometry = renderItem.geometry; + const material = overrideMaterial === null ? renderItem.material : overrideMaterial; + const group = renderItem.group; - currentRenderList.push( object, geometry, material, groupOrder, _vector3.z, null ); + if ( object.layers.test( camera.layers ) ) { - } + renderObject( object, scene, camera, geometry, material, group ); } @@ -27609,1059 +29389,1045 @@ } - const children = object.children; - - for ( let i = 0, l = children.length; i < l; i ++ ) { + function renderObject( object, scene, camera, geometry, material, group ) { - projectObject( children[ i ], camera, groupOrder, sortObjects ); + object.onBeforeRender( _this, scene, camera, geometry, material, group ); - } + object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); + object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); - } + material.onBeforeRender( _this, scene, camera, geometry, object, group ); - function renderScene( currentRenderList, scene, camera, viewport ) { + if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) { - const opaqueObjects = currentRenderList.opaque; - const transmissiveObjects = currentRenderList.transmissive; - const transparentObjects = currentRenderList.transparent; + material.side = BackSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - currentRenderState.setupLightsView( camera ); + material.side = FrontSide; + material.needsUpdate = true; + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, scene, camera ); + material.side = DoubleSide; - if ( viewport ) state.viewport( _currentViewport.copy( viewport ) ); + } else { - if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera ); - if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera ); - if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera ); + _this.renderBufferDirect( camera, scene, geometry, material, object, group ); - // Ensure depth buffer writing is enabled so it can be cleared on next render + } - state.buffers.depth.setTest( true ); - state.buffers.depth.setMask( true ); - state.buffers.color.setMask( true ); + object.onAfterRender( _this, scene, camera, geometry, material, group ); - state.setPolygonOffset( false ); + } - } + function getProgram( material, scene, object ) { - function renderTransmissionPass( opaqueObjects, scene, camera ) { + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - const isWebGL2 = capabilities.isWebGL2; + const materialProperties = properties.get( material ); - if ( _transmissionRenderTarget === null ) { + const lights = currentRenderState.state.lights; + const shadowsArray = currentRenderState.state.shadowsArray; - _transmissionRenderTarget = new WebGLRenderTarget( 1, 1, { - generateMipmaps: true, - type: extensions.has( 'EXT_color_buffer_half_float' ) ? HalfFloatType : UnsignedByteType, - minFilter: LinearMipmapLinearFilter, - samples: ( isWebGL2 && _antialias === true ) ? 4 : 0 - } ); + const lightsStateVersion = lights.state.version; - } + const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); + const programCacheKey = programCache.getProgramCacheKey( parameters ); - _this.getDrawingBufferSize( _vector2 ); + let programs = materialProperties.programs; - if ( isWebGL2 ) { + // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change - _transmissionRenderTarget.setSize( _vector2.x, _vector2.y ); + materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; + materialProperties.fog = scene.fog; + materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); - } else { + if ( programs === undefined ) { - _transmissionRenderTarget.setSize( floorPowerOfTwo( _vector2.x ), floorPowerOfTwo( _vector2.y ) ); + // new material - } + material.addEventListener( 'dispose', onMaterialDispose ); - // + programs = new Map(); + materialProperties.programs = programs; - const currentRenderTarget = _this.getRenderTarget(); - _this.setRenderTarget( _transmissionRenderTarget ); - _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; + let program = programs.get( programCacheKey ); - renderObjects( opaqueObjects, scene, camera ); + if ( program !== undefined ) { - _this.toneMapping = currentToneMapping; + // early out if program and light state is identical - textures.updateMultisampleRenderTarget( _transmissionRenderTarget ); - textures.updateRenderTargetMipmap( _transmissionRenderTarget ); + if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { - _this.setRenderTarget( currentRenderTarget ); + updateCommonMaterialProperties( material, parameters ); - } + return program; - function renderObjects( renderList, scene, camera ) { + } - const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null; + } else { - for ( let i = 0, l = renderList.length; i < l; i ++ ) { + parameters.uniforms = programCache.getUniforms( material ); - const renderItem = renderList[ i ]; + material.onBuild( object, parameters, _this ); - const object = renderItem.object; - const geometry = renderItem.geometry; - const material = overrideMaterial === null ? renderItem.material : overrideMaterial; - const group = renderItem.group; + material.onBeforeCompile( parameters, _this ); - if ( object.layers.test( camera.layers ) ) { + program = programCache.acquireProgram( parameters, programCacheKey ); + programs.set( programCacheKey, program ); - renderObject( object, scene, camera, geometry, material, group ); + materialProperties.uniforms = parameters.uniforms; } - } - - } + const uniforms = materialProperties.uniforms; - function renderObject( object, scene, camera, geometry, material, group ) { + if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { - object.onBeforeRender( _this, scene, camera, geometry, material, group ); + uniforms.clippingPlanes = clipping.uniform; - object.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); - object.normalMatrix.getNormalMatrix( object.modelViewMatrix ); + } - material.onBeforeRender( _this, scene, camera, geometry, object, group ); + updateCommonMaterialProperties( material, parameters ); - if ( material.transparent === true && material.side === DoubleSide ) { + // store the light setup it was created for - material.side = BackSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + materialProperties.needsLights = materialNeedsLights( material ); + materialProperties.lightsStateVersion = lightsStateVersion; - material.side = FrontSide; - material.needsUpdate = true; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + if ( materialProperties.needsLights ) { - material.side = DoubleSide; + // wire up the material to this renderer's lighting state - } else { + 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; - _this.renderBufferDirect( camera, scene, geometry, material, object, group ); + 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 - } + } - object.onAfterRender( _this, scene, camera, geometry, material, group ); + materialProperties.currentProgram = program; + materialProperties.uniformsList = null; - } + return program; - function getProgram( material, scene, object ) { + } - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + function getUniformList( materialProperties ) { - const materialProperties = properties.get( material ); + if ( materialProperties.uniformsList === null ) { - const lights = currentRenderState.state.lights; - const shadowsArray = currentRenderState.state.shadowsArray; + const progUniforms = materialProperties.currentProgram.getUniforms(); + materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms ); - const lightsStateVersion = lights.state.version; + } - const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object ); - const programCacheKey = programCache.getProgramCacheKey( parameters ); + return materialProperties.uniformsList; - let programs = materialProperties.programs; + } - // always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change + function updateCommonMaterialProperties( material, parameters ) { - materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null; - materialProperties.fog = scene.fog; - materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment ); + const materialProperties = properties.get( material ); - if ( programs === undefined ) { + materialProperties.outputColorSpace = parameters.outputColorSpace; + materialProperties.batching = parameters.batching; + materialProperties.instancing = parameters.instancing; + materialProperties.instancingColor = parameters.instancingColor; + 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; - // new material + } - material.addEventListener( 'dispose', onMaterialDispose ); + function setProgram( camera, scene, geometry, material, object ) { - programs = new Map(); - materialProperties.programs = programs; + if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... - } + textures.resetTextureUnits(); - let program = programs.get( programCacheKey ); + const fog = scene.fog; + const environment = material.isMeshStandardMaterial ? scene.environment : null; + const colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ); + const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); + const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; + const vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 ); + const morphTargets = !! geometry.morphAttributes.position; + const morphNormals = !! geometry.morphAttributes.normal; + const morphColors = !! geometry.morphAttributes.color; - if ( program !== undefined ) { + let toneMapping = NoToneMapping; - // early out if program and light state is identical + if ( material.toneMapped ) { - if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) { + if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) { - updateCommonMaterialProperties( material, parameters ); + toneMapping = _this.toneMapping; - return program; + } } - } else { + const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; + const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; - parameters.uniforms = programCache.getUniforms( material ); + const materialProperties = properties.get( material ); + const lights = currentRenderState.state.lights; - material.onBuild( object, parameters, _this ); + if ( _clippingEnabled === true ) { - material.onBeforeCompile( parameters, _this ); + if ( _localClippingEnabled === true || camera !== _currentCamera ) { - program = programCache.acquireProgram( parameters, programCacheKey ); - programs.set( programCacheKey, program ); + const useCache = + camera === _currentCamera && + material.id === _currentMaterialId; - materialProperties.uniforms = parameters.uniforms; + // we might want to call this function with some ClippingGroup + // object instead of the material, once it becomes feasible + // (#8465, #8379) + clipping.setState( material, camera, useCache ); - } + } - const uniforms = materialProperties.uniforms; + } - if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) { + // - uniforms.clippingPlanes = clipping.uniform; + let needsProgramChange = false; - } + if ( material.version === materialProperties.__version ) { - updateCommonMaterialProperties( material, parameters ); + if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { - // store the light setup it was created for + needsProgramChange = true; - materialProperties.needsLights = materialNeedsLights( material ); - materialProperties.lightsStateVersion = lightsStateVersion; + } else if ( materialProperties.outputColorSpace !== colorSpace ) { - if ( materialProperties.needsLights ) { + needsProgramChange = true; - // wire up the material to this renderer's lighting state + } else if ( object.isBatchedMesh && materialProperties.batching === false ) { - 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; + needsProgramChange = true; - 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 + } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) { - } + needsProgramChange = true; - const progUniforms = program.getUniforms(); - const uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, uniforms ); + } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { - materialProperties.currentProgram = program; - materialProperties.uniformsList = uniformsList; + needsProgramChange = true; - return program; + } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { - } + needsProgramChange = true; - function updateCommonMaterialProperties( material, parameters ) { + } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { - const materialProperties = properties.get( material ); + needsProgramChange = true; - materialProperties.outputEncoding = parameters.outputEncoding; - materialProperties.instancing = parameters.instancing; - 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; + } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { - } + needsProgramChange = true; - function setProgram( camera, scene, geometry, material, object ) { + } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) { - if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ... + needsProgramChange = true; - textures.resetTextureUnits(); + } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) { - const fog = scene.fog; - const environment = material.isMeshStandardMaterial ? scene.environment : null; - const encoding = ( _currentRenderTarget === null ) ? _this.outputEncoding : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.encoding : LinearEncoding ); - const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment ); - const vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4; - const vertexTangents = !! material.normalMap && !! geometry.attributes.tangent; - const morphTargets = !! geometry.morphAttributes.position; - const morphNormals = !! geometry.morphAttributes.normal; - const morphColors = !! geometry.morphAttributes.color; - const toneMapping = material.toneMapped ? _this.toneMapping : NoToneMapping; + needsProgramChange = true; - const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color; - const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0; + } else if ( materialProperties.envMap !== envMap ) { - const materialProperties = properties.get( material ); - const lights = currentRenderState.state.lights; + needsProgramChange = true; - if ( _clippingEnabled === true ) { + } else if ( material.fog === true && materialProperties.fog !== fog ) { - if ( _localClippingEnabled === true || camera !== _currentCamera ) { + needsProgramChange = true; - const useCache = - camera === _currentCamera && - material.id === _currentMaterialId; + } else if ( materialProperties.numClippingPlanes !== undefined && + ( materialProperties.numClippingPlanes !== clipping.numPlanes || + materialProperties.numIntersection !== clipping.numIntersection ) ) { - // we might want to call this function with some ClippingGroup - // object instead of the material, once it becomes feasible - // (#8465, #8379) - clipping.setState( material, camera, useCache ); + needsProgramChange = true; - } + } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { - } + needsProgramChange = true; - // + } else if ( materialProperties.vertexTangents !== vertexTangents ) { - let needsProgramChange = false; + needsProgramChange = true; - if ( material.version === materialProperties.__version ) { + } else if ( materialProperties.morphTargets !== morphTargets ) { - if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphNormals !== morphNormals ) { - } else if ( materialProperties.outputEncoding !== encoding ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.morphColors !== morphColors ) { - } else if ( object.isInstancedMesh && materialProperties.instancing === false ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( materialProperties.toneMapping !== toneMapping ) { - } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) { + needsProgramChange = true; - needsProgramChange = true; + } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { - } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) { + needsProgramChange = true; - needsProgramChange = true; + } - } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) { + } else { needsProgramChange = true; + materialProperties.__version = material.version; - } else if ( materialProperties.envMap !== envMap ) { + } - needsProgramChange = true; + // - } else if ( material.fog === true && materialProperties.fog !== fog ) { + let program = materialProperties.currentProgram; - needsProgramChange = true; + if ( needsProgramChange === true ) { - } else if ( materialProperties.numClippingPlanes !== undefined && - ( materialProperties.numClippingPlanes !== clipping.numPlanes || - materialProperties.numIntersection !== clipping.numIntersection ) ) { + program = getProgram( material, scene, object ); - needsProgramChange = true; + } - } else if ( materialProperties.vertexAlphas !== vertexAlphas ) { + let refreshProgram = false; + let refreshMaterial = false; + let refreshLights = false; - needsProgramChange = true; + const p_uniforms = program.getUniforms(), + m_uniforms = materialProperties.uniforms; - } else if ( materialProperties.vertexTangents !== vertexTangents ) { + if ( state.useProgram( program.program ) ) { - needsProgramChange = true; + refreshProgram = true; + refreshMaterial = true; + refreshLights = true; - } else if ( materialProperties.morphTargets !== morphTargets ) { + } - needsProgramChange = true; + if ( material.id !== _currentMaterialId ) { - } else if ( materialProperties.morphNormals !== morphNormals ) { + _currentMaterialId = material.id; - needsProgramChange = true; + refreshMaterial = true; - } else if ( materialProperties.morphColors !== morphColors ) { + } - needsProgramChange = true; + if ( refreshProgram || _currentCamera !== camera ) { - } else if ( materialProperties.toneMapping !== toneMapping ) { + // common camera uniforms - needsProgramChange = true; + p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); - } else if ( capabilities.isWebGL2 === true && materialProperties.morphTargetsCount !== morphTargetsCount ) { + const uCamPos = p_uniforms.map.cameraPosition; - needsProgramChange = true; + if ( uCamPos !== undefined ) { - } + uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) ); - } else { + } - needsProgramChange = true; - materialProperties.__version = material.version; + if ( capabilities.logarithmicDepthBuffer ) { - } + p_uniforms.setValue( _gl, 'logDepthBufFC', + 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); - // + } - let program = materialProperties.currentProgram; + // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067 - if ( needsProgramChange === true ) { + if ( material.isMeshPhongMaterial || + material.isMeshToonMaterial || + material.isMeshLambertMaterial || + material.isMeshBasicMaterial || + material.isMeshStandardMaterial || + material.isShaderMaterial ) { - program = getProgram( material, scene, object ); + p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); - } + } - let refreshProgram = false; - let refreshMaterial = false; - let refreshLights = false; + if ( _currentCamera !== camera ) { - const p_uniforms = program.getUniforms(), - m_uniforms = materialProperties.uniforms; + _currentCamera = camera; - if ( state.useProgram( program.program ) ) { + // lighting uniforms depend on the camera so enforce an update + // now, in case this material supports lights - or later, when + // the next material that does gets activated: - refreshProgram = true; - refreshMaterial = true; - refreshLights = true; + refreshMaterial = true; // set to true on material change + refreshLights = true; // remains set until update done - } + } - if ( material.id !== _currentMaterialId ) { + } - _currentMaterialId = material.id; + // skinning and morph target uniforms must be set even if material didn't change + // auto-setting of texture unit for bone and morph texture must go before other textures + // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures - refreshMaterial = true; + if ( object.isSkinnedMesh ) { - } + p_uniforms.setOptional( _gl, object, 'bindMatrix' ); + p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); - if ( refreshProgram || _currentCamera !== camera ) { + const skeleton = object.skeleton; - p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix ); + if ( skeleton ) { - if ( capabilities.logarithmicDepthBuffer ) { + if ( capabilities.floatVertexTextures ) { - p_uniforms.setValue( _gl, 'logDepthBufFC', - 2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) ); + if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); - } + p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - if ( _currentCamera !== camera ) { + } else { - _currentCamera = camera; + console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); - // lighting uniforms depend on the camera so enforce an update - // now, in case this material supports lights - or later, when - // the next material that does gets activated: + } - refreshMaterial = true; // set to true on material change - refreshLights = true; // remains set until update done + } } - // load material specific uniforms - // (shader material also gets them for the sake of genericity) + if ( object.isBatchedMesh ) { - if ( material.isShaderMaterial || - material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshStandardMaterial || - material.envMap ) { + p_uniforms.setOptional( _gl, object, 'batchingTexture' ); + p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures ); - const uCamPos = p_uniforms.map.cameraPosition; + } - if ( uCamPos !== undefined ) { + const morphAttributes = geometry.morphAttributes; - uCamPos.setValue( _gl, - _vector3.setFromMatrixPosition( camera.matrixWorld ) ); + if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { - } + morphtargets.update( object, geometry, program ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial ) { + if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { - p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true ); + materialProperties.receiveShadow = object.receiveShadow; + p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); } - if ( material.isMeshPhongMaterial || - material.isMeshToonMaterial || - material.isMeshLambertMaterial || - material.isMeshBasicMaterial || - material.isMeshStandardMaterial || - material.isShaderMaterial || - material.isShadowMaterial || - object.isSkinnedMesh ) { + // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 - p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse ); + if ( material.isMeshGouraudMaterial && material.envMap !== null ) { - } + m_uniforms.envMap.value = envMap; - } + m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; - // skinning and morph target uniforms must be set even if material didn't change - // auto-setting of texture unit for bone and morph texture must go before other textures - // otherwise textures used for skinning and morphing can take over texture units reserved for other material textures + } - if ( object.isSkinnedMesh ) { + if ( refreshMaterial ) { - p_uniforms.setOptional( _gl, object, 'bindMatrix' ); - p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' ); + p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); - const skeleton = object.skeleton; + if ( materialProperties.needsLights ) { + + // the current material requires lighting info - if ( skeleton ) { + // note: all lighting uniforms are always set correctly + // they simply reference the renderer's state for their + // values + // + // use the current material's .needsUpdate flags to set + // the GL state when required - if ( capabilities.floatVertexTextures ) { + markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); - if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture(); + } - p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures ); - p_uniforms.setValue( _gl, 'boneTextureSize', skeleton.boneTextureSize ); + // refresh uniforms common to several materials - } else { + if ( fog && material.fog === true ) { - console.warn( 'THREE.WebGLRenderer: SkinnedMesh can only be used with WebGL 2. With WebGL 1 OES_texture_float and vertex textures support is required.' ); + materials.refreshFogUniforms( m_uniforms, fog ); } + materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + } - } + if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { - const morphAttributes = geometry.morphAttributes; + WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures ); + material.uniformsNeedUpdate = false; - if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined && capabilities.isWebGL2 === true ) ) { + } - morphtargets.update( object, geometry, material, program ); + if ( material.isSpriteMaterial ) { - } + p_uniforms.setValue( _gl, 'center', object.center ); - if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) { + } - materialProperties.receiveShadow = object.receiveShadow; - p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow ); + // common matrices - } + p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); + p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); + p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); - // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512 + // UBOs - if ( material.isMeshGouraudMaterial && material.envMap !== null ) { + if ( material.isShaderMaterial || material.isRawShaderMaterial ) { - m_uniforms.envMap.value = envMap; + const groups = material.uniformsGroups; - m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1; + for ( let i = 0, l = groups.length; i < l; i ++ ) { - } + if ( capabilities.isWebGL2 ) { - if ( refreshMaterial ) { + const group = groups[ i ]; - p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure ); + uniformsGroups.update( group, program ); + uniformsGroups.bind( group, program ); - if ( materialProperties.needsLights ) { + } else { - // the current material requires lighting info + console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); - // note: all lighting uniforms are always set correctly - // they simply reference the renderer's state for their - // values - // - // use the current material's .needsUpdate flags to set - // the GL state when required + } - markUniformsLightsNeedsUpdate( m_uniforms, refreshLights ); + } } - // refresh uniforms common to several materials + return program; + + } + + // If uniforms are marked as clean, they don't need to be loaded to the GPU. + + function markUniformsLightsNeedsUpdate( uniforms, value ) { - if ( fog && material.fog === true ) { + uniforms.ambientLightColor.needsUpdate = value; + uniforms.lightProbe.needsUpdate = value; - materials.refreshFogUniforms( m_uniforms, fog ); + 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; - } + } - materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, _transmissionRenderTarget ); + function materialNeedsLights( material ) { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); + return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || + material.isMeshStandardMaterial || material.isShadowMaterial || + ( material.isShaderMaterial && material.lights === true ); } - if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) { + this.getActiveCubeFace = function () { - WebGLUniforms.upload( _gl, materialProperties.uniformsList, m_uniforms, textures ); - material.uniformsNeedUpdate = false; + return _currentActiveCubeFace; - } + }; - if ( material.isSpriteMaterial ) { + this.getActiveMipmapLevel = function () { - p_uniforms.setValue( _gl, 'center', object.center ); + return _currentActiveMipmapLevel; - } + }; - // common matrices + this.getRenderTarget = function () { - p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix ); - p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix ); - p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld ); + return _currentRenderTarget; + + }; - // UBOs + this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { - if ( material.isShaderMaterial || material.isRawShaderMaterial ) { + properties.get( renderTarget.texture ).__webglTexture = colorTexture; + properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; - const groups = material.uniformsGroups; + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__hasExternalTextures = true; - for ( let i = 0, l = groups.length; i < l; i ++ ) { + if ( renderTargetProperties.__hasExternalTextures ) { - if ( capabilities.isWebGL2 ) { + renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; - const group = groups[ i ]; + if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { - uniformsGroups.update( group, program ); - uniformsGroups.bind( group, program ); + // The multisample_render_to_texture extension doesn't work properly if there + // are midframe flushes and an external depth buffer. Disable use of the extension. + if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { - } else { + console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); + renderTargetProperties.__useRenderToTexture = false; - console.warn( 'THREE.WebGLRenderer: Uniform Buffer Objects can only be used with WebGL 2.' ); + } } } - } + }; - return program; + this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { - } + const renderTargetProperties = properties.get( renderTarget ); + renderTargetProperties.__webglFramebuffer = defaultFramebuffer; + renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; - // If uniforms are marked as clean, they don't need to be loaded to the GPU. + }; - function markUniformsLightsNeedsUpdate( uniforms, value ) { + this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { - uniforms.ambientLightColor.needsUpdate = value; - uniforms.lightProbe.needsUpdate = value; + _currentRenderTarget = renderTarget; + _currentActiveCubeFace = activeCubeFace; + _currentActiveMipmapLevel = activeMipmapLevel; - 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; + let useDefaultFramebuffer = true; + let framebuffer = null; + let isCube = false; + let isRenderTarget3D = false; - } + if ( renderTarget ) { - function materialNeedsLights( material ) { + const renderTargetProperties = properties.get( renderTarget ); - return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial || - material.isMeshStandardMaterial || material.isShadowMaterial || - ( material.isShaderMaterial && material.lights === true ); + if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { - } + // We need to make sure to rebind the framebuffer. + state.bindFramebuffer( _gl.FRAMEBUFFER, null ); + useDefaultFramebuffer = false; - this.getActiveCubeFace = function () { + } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { - return _currentActiveCubeFace; + textures.setupRenderTarget( renderTarget ); - }; + } else if ( renderTargetProperties.__hasExternalTextures ) { - this.getActiveMipmapLevel = function () { + // Color and depth texture must be rebound in order for the swapchain to update. + textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); - return _currentActiveMipmapLevel; + } - }; + const texture = renderTarget.texture; - this.getRenderTarget = function () { + if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - return _currentRenderTarget; + isRenderTarget3D = true; - }; + } - this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) { + const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; - properties.get( renderTarget.texture ).__webglTexture = colorTexture; - properties.get( renderTarget.depthTexture ).__webglTexture = depthTexture; + if ( renderTarget.isWebGLCubeRenderTarget ) { - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__hasExternalTextures = true; + if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) { - if ( renderTargetProperties.__hasExternalTextures ) { + framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ]; - renderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined; + } else { - if ( ! renderTargetProperties.__autoAllocateDepthBuffer ) { + framebuffer = __webglFramebuffer[ activeCubeFace ]; - // The multisample_render_to_texture extension doesn't work properly if there - // are midframe flushes and an external depth buffer. Disable use of the extension. - if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) { + } - console.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' ); - renderTargetProperties.__useRenderToTexture = false; + isCube = true; - } + } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { - } + framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; - } + } else { - }; + if ( Array.isArray( __webglFramebuffer ) ) { - this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) { + framebuffer = __webglFramebuffer[ activeMipmapLevel ]; - const renderTargetProperties = properties.get( renderTarget ); - renderTargetProperties.__webglFramebuffer = defaultFramebuffer; - renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined; + } else { - }; + framebuffer = __webglFramebuffer; - this.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) { + } - _currentRenderTarget = renderTarget; - _currentActiveCubeFace = activeCubeFace; - _currentActiveMipmapLevel = activeMipmapLevel; + } - let useDefaultFramebuffer = true; - let framebuffer = null; - let isCube = false; - let isRenderTarget3D = false; + _currentViewport.copy( renderTarget.viewport ); + _currentScissor.copy( renderTarget.scissor ); + _currentScissorTest = renderTarget.scissorTest; - if ( renderTarget ) { + } else { - const renderTargetProperties = properties.get( renderTarget ); + _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); + _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); + _currentScissorTest = _scissorTest; - if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) { + } - // We need to make sure to rebind the framebuffer. - state.bindFramebuffer( 36160, null ); - useDefaultFramebuffer = false; + const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - } else if ( renderTargetProperties.__webglFramebuffer === undefined ) { + if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { - textures.setupRenderTarget( renderTarget ); + state.drawBuffers( renderTarget, framebuffer ); - } else if ( renderTargetProperties.__hasExternalTextures ) { + } - // Color and depth texture must be rebound in order for the swapchain to update. - textures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture ); + state.viewport( _currentViewport ); + state.scissor( _currentScissor ); + state.setScissorTest( _currentScissorTest ); - } + if ( isCube ) { - const texture = renderTarget.texture; + const textureProperties = properties.get( renderTarget.texture ); + _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); - if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + } else if ( isRenderTarget3D ) { - isRenderTarget3D = true; + const textureProperties = properties.get( renderTarget.texture ); + const layer = activeCubeFace || 0; + _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); } - const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer; + _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + + }; + + this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { - if ( renderTarget.isWebGLCubeRenderTarget ) { + if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { - framebuffer = __webglFramebuffer[ activeCubeFace ]; - isCube = true; + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); + return; - } else if ( ( capabilities.isWebGL2 && renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) { + } - framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer; + let framebuffer = properties.get( renderTarget ).__webglFramebuffer; - } else { + if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { - framebuffer = __webglFramebuffer; + framebuffer = framebuffer[ activeCubeFaceIndex ]; } - _currentViewport.copy( renderTarget.viewport ); - _currentScissor.copy( renderTarget.scissor ); - _currentScissorTest = renderTarget.scissorTest; + if ( framebuffer ) { - } else { + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor(); - _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor(); - _currentScissorTest = _scissorTest; + try { - } + const texture = renderTarget.texture; + const textureFormat = texture.format; + const textureType = texture.type; - const framebufferBound = state.bindFramebuffer( 36160, framebuffer ); + if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) { - if ( framebufferBound && capabilities.drawBuffers && useDefaultFramebuffer ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); + return; - state.drawBuffers( renderTarget, framebuffer ); + } - } + const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); - state.viewport( _currentViewport ); - state.scissor( _currentScissor ); - state.setScissorTest( _currentScissorTest ); + if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( _gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513) + ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox + ! halfFloatSupportedByExt ) { - if ( isCube ) { + console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); + return; - const textureProperties = properties.get( renderTarget.texture ); - _gl.framebufferTexture2D( 36160, 36064, 34069 + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel ); + } - } else if ( isRenderTarget3D ) { + // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) - const textureProperties = properties.get( renderTarget.texture ); - const layer = activeCubeFace || 0; - _gl.framebufferTextureLayer( 36160, 36064, textureProperties.__webglTexture, activeMipmapLevel || 0, layer ); + if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { - } + _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); - _currentMaterialId = - 1; // reset current material to ensure correct uniform bindings + } - }; + } finally { - this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) { + // restore framebuffer of current render target if necessary - if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) { + const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; + state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' ); - return; + } - } + } - let framebuffer = properties.get( renderTarget ).__webglFramebuffer; + }; - if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) { + this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { - framebuffer = framebuffer[ activeCubeFaceIndex ]; + const levelScale = Math.pow( 2, - level ); + const width = Math.floor( texture.image.width * levelScale ); + const height = Math.floor( texture.image.height * levelScale ); - } + textures.setTexture2D( texture, 0 ); - if ( framebuffer ) { + _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, position.x, position.y, width, height ); - state.bindFramebuffer( 36160, framebuffer ); + state.unbindTexture(); - try { + }; - const texture = renderTarget.texture; - const textureFormat = texture.format; - const textureType = texture.type; + this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { - if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== _gl.getParameter( 35739 ) ) { + const width = srcTexture.image.width; + const height = srcTexture.image.height; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' ); - return; + textures.setTexture2D( dstTexture, 0 ); - } + // As another texture upload may have changed pixelStorei + // parameters, make sure they are correct for the dstTexture + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || ( capabilities.isWebGL2 && extensions.has( 'EXT_color_buffer_float' ) ) ); + if ( srcTexture.isDataTexture ) { - if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== _gl.getParameter( 35738 ) && // Edge and Chrome Mac < 52 (#9513) - ! ( textureType === FloatType && ( capabilities.isWebGL2 || extensions.has( 'OES_texture_float' ) || extensions.has( 'WEBGL_color_buffer_float' ) ) ) && // Chrome Mac >= 52 and Firefox - ! halfFloatSupportedByExt ) { + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); - console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' ); - return; + } else { - } + if ( srcTexture.isCompressedTexture ) { - // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604) + _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); - if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) { + } else { - _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer ); + _gl.texSubImage2D( _gl.TEXTURE_2D, level, position.x, position.y, glFormat, glType, srcTexture.image ); } - } finally { - - // restore framebuffer of current render target if necessary + } - const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null; - state.bindFramebuffer( 36160, framebuffer ); + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D ); - } + state.unbindTexture(); - } + }; - }; + this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { - this.copyFramebufferToTexture = function ( position, texture, level = 0 ) { + if ( _this.isWebGL1Renderer ) { - const levelScale = Math.pow( 2, - level ); - const width = Math.floor( texture.image.width * levelScale ); - const height = Math.floor( texture.image.height * levelScale ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); + return; - textures.setTexture2D( texture, 0 ); + } - _gl.copyTexSubImage2D( 3553, level, 0, 0, position.x, position.y, width, height ); + const width = sourceBox.max.x - sourceBox.min.x + 1; + const height = sourceBox.max.y - sourceBox.min.y + 1; + const depth = sourceBox.max.z - sourceBox.min.z + 1; + const glFormat = utils.convert( dstTexture.format ); + const glType = utils.convert( dstTexture.type ); + let glTarget; - state.unbindTexture(); + if ( dstTexture.isData3DTexture ) { - }; + textures.setTexture3D( dstTexture, 0 ); + glTarget = _gl.TEXTURE_3D; - this.copyTextureToTexture = function ( position, srcTexture, dstTexture, level = 0 ) { + } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) { - const width = srcTexture.image.width; - const height = srcTexture.image.height; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); + textures.setTexture2DArray( dstTexture, 0 ); + glTarget = _gl.TEXTURE_2D_ARRAY; - textures.setTexture2D( dstTexture, 0 ); + } else { - // As another texture upload may have changed pixelStorei - // parameters, make sure they are correct for the dstTexture - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); + return; - if ( srcTexture.isDataTexture ) { + } - _gl.texSubImage2D( 3553, level, position.x, position.y, width, height, glFormat, glType, srcTexture.image.data ); + _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY ); + _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha ); + _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment ); - } else { + const unpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH ); + const unpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT ); + const unpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS ); + const unpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS ); + const unpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES ); - if ( srcTexture.isCompressedTexture ) { + const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image; - _gl.compressedTexSubImage2D( 3553, level, position.x, position.y, srcTexture.mipmaps[ 0 ].width, srcTexture.mipmaps[ 0 ].height, glFormat, srcTexture.mipmaps[ 0 ].data ); + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, sourceBox.min.x ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, sourceBox.min.y ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, sourceBox.min.z ); - } else { + if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { - _gl.texSubImage2D( 3553, level, position.x, position.y, glFormat, glType, srcTexture.image ); + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); - } + } else { - } + if ( srcTexture.isCompressedArrayTexture ) { - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( 3553 ); + console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); + _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); - state.unbindTexture(); + } else { - }; + _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); - this.copyTextureToTexture3D = function ( sourceBox, position, srcTexture, dstTexture, level = 0 ) { + } - if ( _this.isWebGL1Renderer ) { + } - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: can only be used with WebGL2.' ); - return; + _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, unpackRowLen ); + _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, unpackImageHeight ); + _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, unpackSkipPixels ); + _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, unpackSkipRows ); + _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, unpackSkipImages ); - } + // Generate mipmaps only when copying level 0 + if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); - const width = sourceBox.max.x - sourceBox.min.x + 1; - const height = sourceBox.max.y - sourceBox.min.y + 1; - const depth = sourceBox.max.z - sourceBox.min.z + 1; - const glFormat = utils.convert( dstTexture.format ); - const glType = utils.convert( dstTexture.type ); - let glTarget; + state.unbindTexture(); - if ( dstTexture.isData3DTexture ) { + }; - textures.setTexture3D( dstTexture, 0 ); - glTarget = 32879; + this.initTexture = function ( texture ) { - } else if ( dstTexture.isDataArrayTexture ) { + if ( texture.isCubeTexture ) { - textures.setTexture2DArray( dstTexture, 0 ); - glTarget = 35866; + textures.setTextureCube( texture, 0 ); - } else { + } else if ( texture.isData3DTexture ) { - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' ); - return; + textures.setTexture3D( texture, 0 ); - } + } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { - _gl.pixelStorei( 37440, dstTexture.flipY ); - _gl.pixelStorei( 37441, dstTexture.premultiplyAlpha ); - _gl.pixelStorei( 3317, dstTexture.unpackAlignment ); + textures.setTexture2DArray( texture, 0 ); - const unpackRowLen = _gl.getParameter( 3314 ); - const unpackImageHeight = _gl.getParameter( 32878 ); - const unpackSkipPixels = _gl.getParameter( 3316 ); - const unpackSkipRows = _gl.getParameter( 3315 ); - const unpackSkipImages = _gl.getParameter( 32877 ); + } else { - const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ 0 ] : srcTexture.image; + textures.setTexture2D( texture, 0 ); - _gl.pixelStorei( 3314, image.width ); - _gl.pixelStorei( 32878, image.height ); - _gl.pixelStorei( 3316, sourceBox.min.x ); - _gl.pixelStorei( 3315, sourceBox.min.y ); - _gl.pixelStorei( 32877, sourceBox.min.z ); + } - if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) { + state.unbindTexture(); - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image.data ); + }; - } else { + this.resetState = function () { - if ( srcTexture.isCompressedArrayTexture ) { + _currentActiveCubeFace = 0; + _currentActiveMipmapLevel = 0; + _currentRenderTarget = null; - console.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: untested support for compressed srcTexture.' ); - _gl.compressedTexSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, image.data ); + state.reset(); + bindingStates.reset(); - } else { + }; - _gl.texSubImage3D( glTarget, level, position.x, position.y, position.z, width, height, depth, glFormat, glType, image ); + if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { - } + __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); } - _gl.pixelStorei( 3314, unpackRowLen ); - _gl.pixelStorei( 32878, unpackImageHeight ); - _gl.pixelStorei( 3316, unpackSkipPixels ); - _gl.pixelStorei( 3315, unpackSkipRows ); - _gl.pixelStorei( 32877, unpackSkipImages ); + } - // Generate mipmaps only when copying level 0 - if ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget ); + get coordinateSystem() { - state.unbindTexture(); + return WebGLCoordinateSystem; - }; + } - this.initTexture = function ( texture ) { + get outputColorSpace() { - if ( texture.isCubeTexture ) { + return this._outputColorSpace; - textures.setTextureCube( texture, 0 ); + } - } else if ( texture.isData3DTexture ) { + set outputColorSpace( colorSpace ) { - textures.setTexture3D( texture, 0 ); + this._outputColorSpace = colorSpace; - } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) { + const gl = this.getContext(); + gl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb'; + gl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb'; - textures.setTexture2DArray( texture, 0 ); + } - } else { + get outputEncoding() { // @deprecated, r152 - textures.setTexture2D( texture, 0 ); + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + return this.outputColorSpace === SRGBColorSpace ? sRGBEncoding : LinearEncoding; - } + } - state.unbindTexture(); + set outputEncoding( encoding ) { // @deprecated, r152 - }; + console.warn( 'THREE.WebGLRenderer: Property .outputEncoding has been removed. Use .outputColorSpace instead.' ); + this.outputColorSpace = encoding === sRGBEncoding ? SRGBColorSpace : LinearSRGBColorSpace; - this.resetState = function () { + } - _currentActiveCubeFace = 0; - _currentActiveMipmapLevel = 0; - _currentRenderTarget = null; + get useLegacyLights() { // @deprecated, r155 - state.reset(); - bindingStates.reset(); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + return this._useLegacyLights; - }; + } - if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) { + set useLegacyLights( value ) { // @deprecated, r155 - __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) ); + console.warn( 'THREE.WebGLRenderer: The property .useLegacyLights has been deprecated. Migrate your lighting according to the following guide: https://discourse.threejs.org/t/updates-to-lighting-in-three-js-r155/53733.' ); + this._useLegacyLights = value; } @@ -28722,29 +30488,13 @@ const data = super.toJSON( meta ); if ( this.fog !== null ) data.object.fog = this.fog.toJSON(); - if ( this.backgroundBlurriness > 0 ) data.backgroundBlurriness = this.backgroundBlurriness; - if ( this.backgroundIntensity !== 1 ) data.backgroundIntensity = this.backgroundIntensity; + if ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness; + if ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity; return data; } - // @deprecated - - get autoUpdate() { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - return this.matrixWorldAutoUpdate; - - } - - set autoUpdate( value ) { - - console.warn( 'THREE.Scene: autoUpdate was renamed to matrixWorldAutoUpdate in r144.' ); - this.matrixWorldAutoUpdate = value; - - } - } class SphereGeometry extends BufferGeometry { @@ -28795,11 +30545,11 @@ let uOffset = 0; - if ( iy == 0 && thetaStart == 0 ) { + if ( iy === 0 && thetaStart === 0 ) { uOffset = 0.5 / widthSegments; - } else if ( iy == heightSegments && thetaEnd == Math.PI ) { + } else if ( iy === heightSegments && thetaEnd === Math.PI ) { uOffset = - 0.5 / widthSegments; @@ -28861,6 +30611,16 @@ } + copy( source ) { + + super.copy( source ); + + this.parameters = Object.assign( {}, source.parameters ); + + return this; + + } + static fromJSON( data ) { return new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); @@ -29231,6 +30991,8 @@ } + Loader.DEFAULT_MATERIAL_NAME = '__DEFAULT'; + class ImageLoader extends Loader { constructor( manager ) { @@ -29532,6 +31294,7 @@ * The azimuthal angle (theta) is measured from the positive z-axis. */ + class Spherical { constructor( radius = 1, phi = 0, theta = 0 ) { @@ -29630,7 +31393,7 @@ } - // This set of controls performs orbiting, dollying (zooming), and panning. + // OrbitControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). // // Orbit - left mouse / touch: one-finger move @@ -29640,6 +31403,9 @@ const _changeEvent = { type: 'change' }; const _startEvent = { type: 'start' }; const _endEvent = { type: 'end' }; + const _ray = new Ray(); + const _plane = new Plane(); + const TILT_LIMIT = Math.cos( 70 * MathUtils.DEG2RAD ); class OrbitControls extends EventDispatcher { @@ -29657,6 +31423,9 @@ // "target" sets the location of focus, where the object orbits around this.target = new Vector3(); + // Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect + this.cursor = new Vector3(); + // How far you can dolly in and out ( PerspectiveCamera only ) this.minDistance = 0; this.maxDistance = Infinity; @@ -29665,6 +31434,10 @@ this.minZoom = 0; this.maxZoom = Infinity; + // Limit camera target within a spherical area around the cursor + this.minTargetRadius = 0; + this.maxTargetRadius = Infinity; + // How far you can orbit vertically, upper and lower limits. // Range is 0 to Math.PI radians. this.minPolarAngle = 0; // radians @@ -29694,6 +31467,7 @@ this.panSpeed = 1.0; this.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up this.keyPanSpeed = 7.0; // pixels moved per arrow key push + this.zoomToCursor = false; // Set to true to automatically rotate around the target // If auto-rotate is enabled, you must call controls.update() in your animation loop @@ -29746,6 +31520,13 @@ }; + this.stopListenToKeyEvents = function () { + + this._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + this._domElementKeyEvents = null; + + }; + this.saveState = function () { scope.target0.copy( scope.target ); @@ -29780,10 +31561,11 @@ const lastPosition = new Vector3(); const lastQuaternion = new Quaternion(); + const lastTargetPosition = new Vector3(); const twoPI = 2 * Math.PI; - return function update() { + return function update( deltaTime = null ) { const position = scope.object.position; @@ -29797,7 +31579,7 @@ if ( scope.autoRotate && state === STATE.NONE ) { - rotateLeft( getAutoRotationAngle() ); + rotateLeft( getAutoRotationAngle( deltaTime ) ); } @@ -29844,11 +31626,6 @@ spherical.makeSafe(); - spherical.radius *= scale; - - // restrict radius to be between desired limits - spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) ); - // move target to panned location if ( scope.enableDamping === true ) { @@ -29861,6 +31638,23 @@ } + // Limit the target distance from the cursor to create a sphere around the center of interest + scope.target.sub( scope.cursor ); + scope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius ); + scope.target.add( scope.cursor ); + + // adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera + // we adjust zoom later in these cases + if ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) { + + spherical.radius = clampDistance( spherical.radius ); + + } else { + + spherical.radius = clampDistance( spherical.radius * scale ); + + } + offset.setFromSpherical( spherical ); // rotate offset back to "camera-up-vector-is-up" space @@ -29885,7 +31679,91 @@ } + // adjust camera position + let zoomChanged = false; + if ( scope.zoomToCursor && performCursorZoom ) { + + let newRadius = null; + if ( scope.object.isPerspectiveCamera ) { + + // move the camera down the pointer ray + // this method avoids floating point error + const prevRadius = offset.length(); + newRadius = clampDistance( prevRadius * scale ); + + const radiusDelta = prevRadius - newRadius; + scope.object.position.addScaledVector( dollyDirection, radiusDelta ); + scope.object.updateMatrixWorld(); + + } else if ( scope.object.isOrthographicCamera ) { + + // adjust the ortho camera position based on zoom changes + const mouseBefore = new Vector3( mouse.x, mouse.y, 0 ); + mouseBefore.unproject( scope.object ); + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + const mouseAfter = new Vector3( mouse.x, mouse.y, 0 ); + mouseAfter.unproject( scope.object ); + + scope.object.position.sub( mouseAfter ).add( mouseBefore ); + scope.object.updateMatrixWorld(); + + newRadius = offset.length(); + + } else { + + console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' ); + scope.zoomToCursor = false; + + } + + // handle the placement of the target + if ( newRadius !== null ) { + + if ( this.screenSpacePanning ) { + + // position the orbit target in front of the new camera position + scope.target.set( 0, 0, - 1 ) + .transformDirection( scope.object.matrix ) + .multiplyScalar( newRadius ) + .add( scope.object.position ); + + } else { + + // get the ray and translation plane to compute target + _ray.origin.copy( scope.object.position ); + _ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix ); + + // if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid + // extremely large values + if ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) { + + object.lookAt( scope.target ); + + } else { + + _plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target ); + _ray.intersectPlane( _plane, scope.target ); + + } + + } + + } + + } else if ( scope.object.isOrthographicCamera ) { + + scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) ); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } + scale = 1; + performCursorZoom = false; // update condition is: // min(camera displacement, camera rotation in radians)^2 > EPS @@ -29893,13 +31771,14 @@ if ( zoomChanged || lastPosition.distanceToSquared( scope.object.position ) > EPS || - 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) { + 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS || + lastTargetPosition.distanceToSquared( scope.target ) > 0 ) { scope.dispatchEvent( _changeEvent ); lastPosition.copy( scope.object.position ); lastQuaternion.copy( scope.object.quaternion ); - zoomChanged = false; + lastTargetPosition.copy( scope.target ); return true; @@ -29916,7 +31795,7 @@ scope.domElement.removeEventListener( 'contextmenu', onContextMenu ); scope.domElement.removeEventListener( 'pointerdown', onPointerDown ); - scope.domElement.removeEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.removeEventListener( 'pointercancel', onPointerUp ); scope.domElement.removeEventListener( 'wheel', onMouseWheel ); scope.domElement.removeEventListener( 'pointermove', onPointerMove ); @@ -29926,6 +31805,7 @@ if ( scope._domElementKeyEvents !== null ) { scope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown ); + scope._domElementKeyEvents = null; } @@ -29960,7 +31840,6 @@ let scale = 1; const panOffset = new Vector3(); - let zoomChanged = false; const rotateStart = new Vector2(); const rotateEnd = new Vector2(); @@ -29974,18 +31853,31 @@ const dollyEnd = new Vector2(); const dollyDelta = new Vector2(); + const dollyDirection = new Vector3(); + const mouse = new Vector2(); + let performCursorZoom = false; + const pointers = []; const pointerPositions = {}; - function getAutoRotationAngle() { + function getAutoRotationAngle( deltaTime ) { + + if ( deltaTime !== null ) { + + return ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime; + + } else { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; - return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + } } - function getZoomScale() { + function getZoomScale( delta ) { - return Math.pow( 0.95, scope.zoomSpeed ); + const normalized_delta = Math.abs( delta ) / ( 100 * ( window.devicePixelRatio | 0 ) ); + return Math.pow( 0.95, scope.zoomSpeed * normalized_delta ); } @@ -30084,16 +31976,10 @@ function dollyOut( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale /= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -30105,16 +31991,10 @@ function dollyIn( dollyScale ) { - if ( scope.object.isPerspectiveCamera ) { + if ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) { scale *= dollyScale; - } else if ( scope.object.isOrthographicCamera ) { - - scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) ); - scope.object.updateProjectionMatrix(); - zoomChanged = true; - } else { console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' ); @@ -30124,6 +32004,35 @@ } + function updateZoomParameters( x, y ) { + + if ( ! scope.zoomToCursor ) { + + return; + + } + + performCursorZoom = true; + + const rect = scope.domElement.getBoundingClientRect(); + const dx = x - rect.left; + const dy = y - rect.top; + const w = rect.width; + const h = rect.height; + + mouse.x = ( dx / w ) * 2 - 1; + mouse.y = - ( dy / h ) * 2 + 1; + + dollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize(); + + } + + function clampDistance( dist ) { + + return Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) ); + + } + // // event callbacks - update the object state // @@ -30136,6 +32045,7 @@ function handleMouseDownDolly( event ) { + updateZoomParameters( event.clientX, event.clientX ); dollyStart.set( event.clientX, event.clientY ); } @@ -30172,11 +32082,11 @@ if ( dollyDelta.y > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( dollyDelta.y ) ); } else if ( dollyDelta.y < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( dollyDelta.y ) ); } @@ -30202,13 +32112,15 @@ function handleMouseWheel( event ) { + updateZoomParameters( event.clientX, event.clientY ); + if ( event.deltaY < 0 ) { - dollyIn( getZoomScale() ); + dollyIn( getZoomScale( event.deltaY ) ); } else if ( event.deltaY > 0 ) { - dollyOut( getZoomScale() ); + dollyOut( getZoomScale( event.deltaY ) ); } @@ -30296,16 +32208,18 @@ } - function handleTouchStartRotate() { + function handleTouchStartRotate( event ) { if ( pointers.length === 1 ) { - rotateStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + rotateStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); rotateStart.set( x, y ); @@ -30313,16 +32227,18 @@ } - function handleTouchStartPan() { + function handleTouchStartPan( event ) { if ( pointers.length === 1 ) { - panStart.set( pointers[ 0 ].pageX, pointers[ 0 ].pageY ); + panStart.set( event.pageX, event.pageY ); } else { - const x = 0.5 * ( pointers[ 0 ].pageX + pointers[ 1 ].pageX ); - const y = 0.5 * ( pointers[ 0 ].pageY + pointers[ 1 ].pageY ); + const position = getSecondPointerPosition( event ); + + const x = 0.5 * ( event.pageX + position.x ); + const y = 0.5 * ( event.pageY + position.y ); panStart.set( x, y ); @@ -30330,10 +32246,12 @@ } - function handleTouchStartDolly() { + function handleTouchStartDolly( event ) { + + const position = getSecondPointerPosition( event ); - const dx = pointers[ 0 ].pageX - pointers[ 1 ].pageX; - const dy = pointers[ 0 ].pageY - pointers[ 1 ].pageY; + const dx = event.pageX - position.x; + const dy = event.pageY - position.y; const distance = Math.sqrt( dx * dx + dy * dy ); @@ -30341,19 +32259,19 @@ } - function handleTouchStartDollyPan() { + function handleTouchStartDollyPan( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enablePan ) handleTouchStartPan(); + if ( scope.enablePan ) handleTouchStartPan( event ); } - function handleTouchStartDollyRotate() { + function handleTouchStartDollyRotate( event ) { - if ( scope.enableZoom ) handleTouchStartDolly(); + if ( scope.enableZoom ) handleTouchStartDolly( event ); - if ( scope.enableRotate ) handleTouchStartRotate(); + if ( scope.enableRotate ) handleTouchStartRotate( event ); } @@ -30428,6 +32346,11 @@ dollyStart.copy( dollyEnd ); + const centerX = ( event.pageX + position.x ) * 0.5; + const centerY = ( event.pageY + position.y ) * 0.5; + + updateZoomParameters( centerX, centerY ); + } function handleTouchMoveDollyPan( event ) { @@ -30497,26 +32420,20 @@ function onPointerUp( event ) { - removePointer( event ); - - if ( pointers.length === 0 ) { - - scope.domElement.releasePointerCapture( event.pointerId ); - - scope.domElement.removeEventListener( 'pointermove', onPointerMove ); - scope.domElement.removeEventListener( 'pointerup', onPointerUp ); + removePointer( event ); - } + if ( pointers.length === 0 ) { - scope.dispatchEvent( _endEvent ); + scope.domElement.releasePointerCapture( event.pointerId ); - state = STATE.NONE; + scope.domElement.removeEventListener( 'pointermove', onPointerMove ); + scope.domElement.removeEventListener( 'pointerup', onPointerUp ); - } + } - function onPointerCancel( event ) { + scope.dispatchEvent( _endEvent ); - removePointer( event ); + state = STATE.NONE; } @@ -30685,7 +32602,7 @@ if ( scope.enableRotate === false ) return; - handleTouchStartRotate(); + handleTouchStartRotate( event ); state = STATE.TOUCH_ROTATE; @@ -30695,7 +32612,7 @@ if ( scope.enablePan === false ) return; - handleTouchStartPan(); + handleTouchStartPan( event ); state = STATE.TOUCH_PAN; @@ -30717,7 +32634,7 @@ if ( scope.enableZoom === false && scope.enablePan === false ) return; - handleTouchStartDollyPan(); + handleTouchStartDollyPan( event ); state = STATE.TOUCH_DOLLY_PAN; @@ -30727,7 +32644,7 @@ if ( scope.enableZoom === false && scope.enableRotate === false ) return; - handleTouchStartDollyRotate(); + handleTouchStartDollyRotate( event ); state = STATE.TOUCH_DOLLY_ROTATE; @@ -30819,7 +32736,7 @@ function addPointer( event ) { - pointers.push( event ); + pointers.push( event.pointerId ); } @@ -30829,7 +32746,7 @@ for ( let i = 0; i < pointers.length; i ++ ) { - if ( pointers[ i ].pointerId == event.pointerId ) { + if ( pointers[ i ] == event.pointerId ) { pointers.splice( i, 1 ); return; @@ -30857,9 +32774,9 @@ function getSecondPointerPosition( event ) { - const pointer = ( event.pointerId === pointers[ 0 ].pointerId ) ? pointers[ 1 ] : pointers[ 0 ]; + const pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ]; - return pointerPositions[ pointer.pointerId ]; + return pointerPositions[ pointerId ]; } @@ -30868,7 +32785,7 @@ scope.domElement.addEventListener( 'contextmenu', onContextMenu ); scope.domElement.addEventListener( 'pointerdown', onPointerDown ); - scope.domElement.addEventListener( 'pointercancel', onPointerCancel ); + scope.domElement.addEventListener( 'pointercancel', onPointerUp ); scope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } ); // force an update at start @@ -30879,10 +32796,8 @@ } - - // This set of controls performs orbiting, dollying (zooming), and panning. + // MapControls performs orbiting, dollying (zooming), and panning. // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). - // This is very similar to OrbitControls, another set of touch behavior // // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish @@ -30896,11 +32811,9 @@ this.screenSpacePanning = false; // pan orthogonal to world-space direction camera.up - this.mouseButtons.LEFT = MOUSE.PAN; - this.mouseButtons.RIGHT = MOUSE.ROTATE; + this.mouseButtons = { LEFT: MOUSE.PAN, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.ROTATE }; - this.touches.ONE = TOUCH.PAN; - this.touches.TWO = TOUCH.DOLLY_ROTATE; + this.touches = { ONE: TOUCH.PAN, TWO: TOUCH.DOLLY_ROTATE }; } @@ -32209,7 +34122,7 @@ class MapView extends Mesh { constructor(root = MapView.PLANAR, provider = new OpenStreetMapsProvider(), heightProvider = null) { - super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0 })); + super(undefined, new MeshBasicMaterial({ transparent: true, opacity: 0.0, depthWrite: false, colorWrite: false })); this.lod = null; this.provider = null; this.heightProvider = null; diff --git a/package.json b/package.json index 52a5714..f2aa879 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@rollup/plugin-typescript": "10.0.1", "@rollup/plugin-node-resolve": "15.0.1", "@types/offscreencanvas": "2019.7.0", - "@types/three": "^0.146.0", + "@types/three": "^0.160.0", "@typescript-eslint/eslint-plugin": "5.47.0", "@typescript-eslint/parser": "5.47.0", "eslint": "8.30.0", @@ -54,7 +54,7 @@ "eslint-plugin-tsdoc": "0.2.17", "eslint-plugin-typescript": "0.14.0", "rollup": "3.8.1", - "three": "^0.147.0", + "three": "^0.160.0", "typedoc": "0.23.23", "typescript": "4.9.4", "http-server": "14.1.1" diff --git a/source/examples/basic.ts b/source/examples/basic.ts index 420b198..52c5502 100644 --- a/source/examples/basic.ts +++ b/source/examples/basic.ts @@ -1,7 +1,7 @@ // @ts-nocheck import {WebGLRenderer, Scene, Color, AmbientLight, PerspectiveCamera} from 'three'; -import {MapControls} from 'three/examples/jsm/controls/OrbitControls.js'; +import {MapControls} from 'three/examples/jsm/controls/MapControls.js'; import {MapView, BingMapsProvider, UnitsUtils} from '../Main'; var canvas = document.getElementById('canvas'); diff --git a/source/examples/providers.ts b/source/examples/providers.ts index 3907caa..8baaa0f 100644 --- a/source/examples/providers.ts +++ b/source/examples/providers.ts @@ -1,7 +1,7 @@ // @ts-nocheck import {WebGLRenderer, Scene, Color, AmbientLight, PerspectiveCamera, DirectionalLight, Vector3} from 'three'; -import {MapControls} from 'three/examples/jsm/controls/OrbitControls.js'; +import {MapControls} from 'three/examples/jsm/controls/MapControls.js'; import {Sky} from 'three/examples/jsm/objects/Sky.js'; import {HereMapsProvider, BingMapsProvider, MapTilerProvider, HeightDebugProvider, DebugProvider, LODRaycast, LODFrustum, LODRadial, UnitsUtils, OpenStreetMapsProvider, OpenMapTilesProvider, MapBoxProvider, MapView} from '../Main'; diff --git a/source/examples/transition.ts b/source/examples/transition.ts index 6133e8b..18a8579 100644 --- a/source/examples/transition.ts +++ b/source/examples/transition.ts @@ -1,7 +1,7 @@ // @ts-nocheck import {WebGLRenderer, Scene, Color, TextureLoader, Mesh, SphereGeometry, MeshBasicMaterial, PerspectiveCamera, MOUSE, AmbientLight, Raycaster, Vector2} from 'three'; -import {MapControls} from 'three/examples/jsm/controls/OrbitControls.js'; +import {MapControls} from 'three/examples/jsm/controls/MapControls.js'; import {UnitsUtils, BingMapsProvider, MapView} from '../Main'; var canvas = document.getElementById('canvas');