Skip to content

⬅️ Back to Table of Contents

📄 three.module.js

📊 Analysis Summary

Metric Count
🔧 Functions 447
🧱 Classes 11
📦 Imports 186
📊 Variables & Constants 1168
🔄 Re-exports 1

📚 Table of Contents

🛠️ File Location:

📂 build/three.module.js

📦 Imports

Name Source
Matrix3 ./three.core.js
Vector2 ./three.core.js
Color ./three.core.js
mergeUniforms ./three.core.js
Vector3 ./three.core.js
CubeUVReflectionMapping ./three.core.js
Mesh ./three.core.js
BoxGeometry ./three.core.js
ShaderMaterial ./three.core.js
BackSide ./three.core.js
cloneUniforms ./three.core.js
Euler ./three.core.js
Matrix4 ./three.core.js
ColorManagement ./three.core.js
SRGBTransfer ./three.core.js
PlaneGeometry ./three.core.js
FrontSide ./three.core.js
getUnlitUniformColorSpace ./three.core.js
IntType ./three.core.js
HalfFloatType ./three.core.js
UnsignedByteType ./three.core.js
FloatType ./three.core.js
RGBAFormat ./three.core.js
Plane ./three.core.js
EquirectangularReflectionMapping ./three.core.js
EquirectangularRefractionMapping ./three.core.js
WebGLCubeRenderTarget ./three.core.js
CubeReflectionMapping ./three.core.js
CubeRefractionMapping ./three.core.js
OrthographicCamera ./three.core.js
PerspectiveCamera ./three.core.js
NoToneMapping ./three.core.js
MeshBasicMaterial ./three.core.js
NoBlending ./three.core.js
WebGLRenderTarget ./three.core.js
BufferGeometry ./three.core.js
BufferAttribute ./three.core.js
LinearSRGBColorSpace ./three.core.js
LinearFilter ./three.core.js
warnOnce ./three.core.js
Uint32BufferAttribute ./three.core.js
Uint16BufferAttribute ./three.core.js
arrayNeedsUint32 ./three.core.js
Vector4 ./three.core.js
DataArrayTexture ./three.core.js
CubeTexture ./three.core.js
Data3DTexture ./three.core.js
LessEqualCompare ./three.core.js
DepthTexture ./three.core.js
Texture ./three.core.js
GLSL3 ./three.core.js
PCFShadowMap ./three.core.js
PCFSoftShadowMap ./three.core.js
VSMShadowMap ./three.core.js
CustomToneMapping ./three.core.js
NeutralToneMapping ./three.core.js
AgXToneMapping ./three.core.js
ACESFilmicToneMapping ./three.core.js
CineonToneMapping ./three.core.js
ReinhardToneMapping ./three.core.js
LinearToneMapping ./three.core.js
LinearTransfer ./three.core.js
AddOperation ./three.core.js
MixOperation ./three.core.js
MultiplyOperation ./three.core.js
UniformsUtils ./three.core.js
DoubleSide ./three.core.js
NormalBlending ./three.core.js
TangentSpaceNormalMap ./three.core.js
ObjectSpaceNormalMap ./three.core.js
Layers ./three.core.js
Frustum ./three.core.js
MeshDepthMaterial ./three.core.js
RGBADepthPacking ./three.core.js
MeshDistanceMaterial ./three.core.js
NearestFilter ./three.core.js
LessEqualDepth ./three.core.js
ReverseSubtractEquation ./three.core.js
SubtractEquation ./three.core.js
AddEquation ./three.core.js
OneMinusConstantAlphaFactor ./three.core.js
ConstantAlphaFactor ./three.core.js
OneMinusConstantColorFactor ./three.core.js
ConstantColorFactor ./three.core.js
OneMinusDstAlphaFactor ./three.core.js
OneMinusDstColorFactor ./three.core.js
OneMinusSrcAlphaFactor ./three.core.js
OneMinusSrcColorFactor ./three.core.js
DstAlphaFactor ./three.core.js
DstColorFactor ./three.core.js
SrcAlphaSaturateFactor ./three.core.js
SrcAlphaFactor ./three.core.js
SrcColorFactor ./three.core.js
OneFactor ./three.core.js
ZeroFactor ./three.core.js
NotEqualDepth ./three.core.js
GreaterDepth ./three.core.js
GreaterEqualDepth ./three.core.js
EqualDepth ./three.core.js
LessDepth ./three.core.js
AlwaysDepth ./three.core.js
NeverDepth ./three.core.js
CullFaceNone ./three.core.js
CullFaceBack ./three.core.js
CullFaceFront ./three.core.js
CustomBlending ./three.core.js
MultiplyBlending ./three.core.js
SubtractiveBlending ./three.core.js
AdditiveBlending ./three.core.js
MinEquation ./three.core.js
MaxEquation ./three.core.js
MirroredRepeatWrapping ./three.core.js
ClampToEdgeWrapping ./three.core.js
RepeatWrapping ./three.core.js
LinearMipmapLinearFilter ./three.core.js
LinearMipmapNearestFilter ./three.core.js
NearestMipmapLinearFilter ./three.core.js
NearestMipmapNearestFilter ./three.core.js
NotEqualCompare ./three.core.js
GreaterCompare ./three.core.js
GreaterEqualCompare ./three.core.js
EqualCompare ./three.core.js
LessCompare ./three.core.js
AlwaysCompare ./three.core.js
NeverCompare ./three.core.js
NoColorSpace ./three.core.js
DepthStencilFormat ./three.core.js
getByteLength ./three.core.js
DepthFormat ./three.core.js
UnsignedIntType ./three.core.js
UnsignedInt248Type ./three.core.js
UnsignedShortType ./three.core.js
createElementNS ./three.core.js
UnsignedShort4444Type ./three.core.js
UnsignedShort5551Type ./three.core.js
UnsignedInt5999Type ./three.core.js
ByteType ./three.core.js
ShortType ./three.core.js
AlphaFormat ./three.core.js
RGBFormat ./three.core.js
RedFormat ./three.core.js
RedIntegerFormat ./three.core.js
RGFormat ./three.core.js
RGIntegerFormat ./three.core.js
RGBAIntegerFormat ./three.core.js
RGB_S3TC_DXT1_Format ./three.core.js
RGBA_S3TC_DXT1_Format ./three.core.js
RGBA_S3TC_DXT3_Format ./three.core.js
RGBA_S3TC_DXT5_Format ./three.core.js
RGB_PVRTC_4BPPV1_Format ./three.core.js
RGB_PVRTC_2BPPV1_Format ./three.core.js
RGBA_PVRTC_4BPPV1_Format ./three.core.js
RGBA_PVRTC_2BPPV1_Format ./three.core.js
RGB_ETC1_Format ./three.core.js
RGB_ETC2_Format ./three.core.js
RGBA_ETC2_EAC_Format ./three.core.js
RGBA_ASTC_4x4_Format ./three.core.js
RGBA_ASTC_5x4_Format ./three.core.js
RGBA_ASTC_5x5_Format ./three.core.js
RGBA_ASTC_6x5_Format ./three.core.js
RGBA_ASTC_6x6_Format ./three.core.js
RGBA_ASTC_8x5_Format ./three.core.js
RGBA_ASTC_8x6_Format ./three.core.js
RGBA_ASTC_8x8_Format ./three.core.js
RGBA_ASTC_10x5_Format ./three.core.js
RGBA_ASTC_10x6_Format ./three.core.js
RGBA_ASTC_10x8_Format ./three.core.js
RGBA_ASTC_10x10_Format ./three.core.js
RGBA_ASTC_12x10_Format ./three.core.js
RGBA_ASTC_12x12_Format ./three.core.js
RGBA_BPTC_Format ./three.core.js
RGB_BPTC_SIGNED_Format ./three.core.js
RGB_BPTC_UNSIGNED_Format ./three.core.js
RED_RGTC1_Format ./three.core.js
SIGNED_RED_RGTC1_Format ./three.core.js
RED_GREEN_RGTC2_Format ./three.core.js
SIGNED_RED_GREEN_RGTC2_Format ./three.core.js
EventDispatcher ./three.core.js
ArrayCamera ./three.core.js
WebXRController ./three.core.js
RAD2DEG ./three.core.js
createCanvasElement ./three.core.js
SRGBColorSpace ./three.core.js
REVISION ./three.core.js
WebGLCoordinateSystem ./three.core.js
probeAsync ./three.core.js

Variables & Constants

Name Type Kind Value Exported
context any let/var null
isAnimating boolean let/var false
animationLoop any let/var null
requestId any let/var null
buffers WeakMap<WeakKey, any> let/var new WeakMap()
array any let/var attribute.array
usage any let/var attribute.usage
size any let/var array.byteLength
type any let/var *not shown*
array any let/var attribute.array
updateRanges any let/var attribute.updateRanges
mergeIndex number let/var 0
previousRange any let/var updateRanges[ mergeIndex ]
range any let/var updateRanges[ i ]
range any let/var updateRanges[ i ]
alphahash_fragment string let/var "#ifdef USE_ALPHAHASH\n\tif ( diffuseColor.a < getAlphaHashThreshold( vPositi...
alphahash_pars_fragment string let/var "#ifdef USE_ALPHAHASH\n\tconst float ALPHA_HASH_SCALE = 0.05;\n\tfloat hash2D...
alphamap_fragment string let/var "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv )....
alphamap_pars_fragment string let/var "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif"
alphatest_fragment string let/var "#ifdef USE_ALPHATEST\n\t#ifdef ALPHA_TO_COVERAGE\n\tdiffuseColor.a = smooths...
alphatest_pars_fragment string let/var "#ifdef USE_ALPHATEST\n\tuniform float alphaTest;\n#endif"
aomap_fragment string let/var "#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vAoMapUv )....
aomap_pars_fragment string let/var "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity...
batching_pars_vertex string let/var "#ifdef USE_BATCHING\n\t#if ! defined( GL_ANGLE_multi_draw )\n\t#define gl_Dr...
batching_vertex string let/var "#ifdef USE_BATCHING\n\tmat4 batchingMatrix = getBatchingMatrix( getIndirectI...
begin_vertex string let/var "vec3 transformed = vec3( position );\n#ifdef USE_ALPHAHASH\n\tvPosition = ve...
beginnormal_vertex string let/var "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangen...
bsdfs string let/var "float G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( con...
iridescence_fragment string let/var "#ifdef USE_IRIDESCENCE\n\tconst mat3 XYZ_TO_REC709 = mat3(\n\t\t 3.2404542, ...
bumpmap_pars_fragment string let/var "#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;...
clipping_planes_fragment string let/var "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#ifdef ALPHA_TO_COVERAGE\n\t\t...
clipping_planes_pars_fragment string let/var "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 c...
clipping_planes_pars_vertex string let/var "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif"
clipping_planes_vertex string let/var "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif"
color_fragment string let/var "#if defined( USE_COLOR_ALPHA )\n\tdiffuseColor *= vColor;\n#elif defined( US...
color_pars_fragment string let/var "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_C...
color_pars_vertex string let/var "#if defined( USE_COLOR_ALPHA )\n\tvarying vec4 vColor;\n#elif defined( USE_C...
color_vertex string let/var "#if defined( USE_COLOR_ALPHA )\n\tvColor = vec4( 1.0 );\n#elif defined( USE_...
common string let/var "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF...
cube_uv_reflection_fragment string let/var "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_minMipLevel 4.0\n\t#define cube...
defaultnormal_vertex string let/var "vec3 transformedNormal = objectNormal;\n#ifdef USE_TANGENT\n\tvec3 transform...
displacementmap_pars_vertex string let/var "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform ...
displacementmap_vertex string let/var "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( t...
emissivemap_fragment string let/var "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vEmis...
emissivemap_pars_fragment string let/var "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif"
colorspace_fragment string let/var "gl_FragColor = linearToOutputTexel( gl_FragColor );"
colorspace_pars_fragment string let/var "vec4 LinearTransferOETF( in vec4 value ) {\n\treturn value;\n}\nvec4 sRGBTra...
envmap_fragment string let/var "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\tif ( i...
envmap_common_pars_fragment string let/var "#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnv...
envmap_pars_fragment string let/var "#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP...
envmap_pars_vertex string let/var "#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) \|\| defined( USE_NORMALMAP ...
envmap_vertex string let/var "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition...
fog_vertex string let/var "#ifdef USE_FOG\n\tvFogDepth = - mvPosition.z;\n#endif"
fog_pars_vertex string let/var "#ifdef USE_FOG\n\tvarying float vFogDepth;\n#endif"
fog_fragment string let/var "#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = 1.0 - exp( - fogDen...
fog_pars_fragment string let/var "#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float vFogDepth;\n\t#ifd...
gradientmap_pars_fragment string let/var "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGr...
lightmap_pars_fragment string let/var "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMap...
lights_lambert_fragment string let/var "LambertMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmateri...
lights_lambert_pars_fragment string let/var "varying vec3 vViewPosition;\nstruct LambertMaterial {\n\tvec3 diffuseColor;\...
lights_pars_begin string let/var "uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\n#if defined( U...
envmap_physical_pars_fragment string let/var "#ifdef USE_ENVMAP\n\tvec3 getIBLIrradiance( const in vec3 normal ) {\n\t\t#i...
lights_toon_fragment string let/var "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;"
lights_toon_pars_fragment string let/var "varying vec3 vViewPosition;\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};...
lights_phong_fragment string let/var "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmat...
lights_phong_pars_fragment string let/var "varying vec3 vViewPosition;\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColo...
lights_physical_fragment string let/var "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0...
lights_physical_pars_fragment string let/var "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat roughness;\n\tvec3 ...
lights_fragment_begin string let/var "\nvec3 geometryPosition = - vViewPosition;\nvec3 geometryNormal = normal;\nv...
lights_fragment_maps string let/var "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapT...
lights_fragment_end string let/var "#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometr...
logdepthbuf_fragment string let/var "#if defined( USE_LOGDEPTHBUF )\n\tgl_FragDepth = vIsPerspective == 0.0 ? gl_...
logdepthbuf_pars_fragment string let/var "#if defined( USE_LOGDEPTHBUF )\n\tuniform float logDepthBufFC;\n\tvarying fl...
logdepthbuf_pars_vertex string let/var "#ifdef USE_LOGDEPTHBUF\n\tvarying float vFragDepth;\n\tvarying float vIsPers...
logdepthbuf_vertex string let/var "#ifdef USE_LOGDEPTHBUF\n\tvFragDepth = 1.0 + gl_Position.w;\n\tvIsPerspectiv...
map_fragment string let/var "#ifdef USE_MAP\n\tvec4 sampledDiffuseColor = texture2D( map, vMapUv );\n\t#i...
map_pars_fragment string let/var "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif"
map_particle_fragment string let/var "#if defined( USE_MAP ) \|\| defined( USE_ALPHAMAP )\n\t#if defined( USE_POIN...
map_particle_pars_fragment string let/var "#if defined( USE_POINTS_UV )\n\tvarying vec2 vUv;\n#else\n\t#if defined( USE...
metalnessmap_fragment string let/var "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMet...
metalnessmap_pars_fragment string let/var "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif"
morphinstance_vertex string let/var "#ifdef USE_INSTANCING_MORPH\n\tfloat morphTargetInfluences[ MORPHTARGETS_COU...
morphcolor_vertex string let/var "#if defined( USE_MORPHCOLORS )\n\tvColor *= morphTargetBaseInfluence;\n\tfor...
morphnormal_vertex string let/var "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tfor ...
morphtarget_pars_vertex string let/var "#ifdef USE_MORPHTARGETS\n\t#ifndef USE_INSTANCING_MORPH\n\t\tuniform float m...
morphtarget_vertex string let/var "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\tfor (...
normal_fragment_begin string let/var "float faceDirection = gl_FrontFacing ? 1.0 : - 1.0;\n#ifdef FLAT_SHADED\n\tv...
normal_fragment_maps string let/var "#ifdef USE_NORMALMAP_OBJECTSPACE\n\tnormal = texture2D( normalMap, vNormalMa...
normal_pars_fragment string let/var "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvary...
normal_pars_vertex string let/var "#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvary...
normal_vertex string let/var "#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef U...
normalmap_pars_fragment string let/var "#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalS...
clearcoat_normal_fragment_b... string let/var "#ifdef USE_CLEARCOAT\n\tvec3 clearcoatNormal = nonPerturbedNormal;\n#endif"
clearcoat_normal_fragment_maps string let/var "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatN...
clearcoat_pars_fragment string let/var "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef U...
iridescence_pars_fragment string let/var "#ifdef USE_IRIDESCENCEMAP\n\tuniform sampler2D iridescenceMap;\n#endif\n#ifd...
opaque_fragment string let/var "#ifdef OPAQUE\ndiffuseColor.a = 1.0;\n#endif\n#ifdef USE_TRANSMISSION\ndiffu...
packing string let/var "vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal )...
premultiplied_alpha_fragment string let/var "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif"
project_vertex string let/var "vec4 mvPosition = vec4( transformed, 1.0 );\n#ifdef USE_BATCHING\n\tmvPositi...
dithering_fragment string let/var "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif"
dithering_pars_fragment string let/var "#ifdef DITHERING\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position ...
roughnessmap_fragment string let/var "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRou...
roughnessmap_pars_fragment string let/var "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif"
shadowmap_pars_fragment string let/var "#if NUM_SPOT_LIGHT_COORDS > 0\n\tvarying vec4 vSpotLightCoord[ NUM_SPOT_LIGH...
shadowmap_pars_vertex string let/var "#if NUM_SPOT_LIGHT_COORDS > 0\n\tuniform mat4 spotLightMatrix[ NUM_SPOT_LIGH...
shadowmap_vertex string let/var "#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 \|\| NUM_POINT...
shadowmask_pars_fragment string let/var "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#i...
skinbase_vertex string let/var "#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4...
skinning_pars_vertex string let/var "#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixIn...
skinning_vertex string let/var "#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0...
skinnormal_vertex string let/var "#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinW...
specularmap_fragment string let/var "float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = text...
specularmap_pars_fragment string let/var "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif"
tonemapping_fragment string let/var "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor....
tonemapping_pars_fragment string let/var "#ifndef saturate\n#define saturate( a ) clamp( a, 0.0, 1.0 )\n#endif\nunifor...
transmission_fragment string let/var "#ifdef USE_TRANSMISSION\n\tmaterial.transmission = transmission;\n\tmaterial...
transmission_pars_fragment string let/var "#ifdef USE_TRANSMISSION\n\tuniform float transmission;\n\tuniform float thic...
uv_pars_fragment string let/var "#if defined( USE_UV ) \|\| defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#...
uv_pars_vertex string let/var "#if defined( USE_UV ) \|\| defined( USE_ANISOTROPY )\n\tvarying vec2 vUv;\n#...
uv_vertex string let/var "#if defined( USE_UV ) \|\| defined( USE_ANISOTROPY )\n\tvUv = vec3( uv, 1 )....
worldpos_vertex string let/var "#if defined( USE_ENVMAP ) \|\| defined( DISTANCE ) \|\| defined ( USE_SHADOW...
vertex$h "varying vec2 vUv;\nuniform mat3 uvTr... let/var "varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTra...
fragment$h "uniform sampler2D t2D;\nuniform floa... let/var "uniform sampler2D t2D;\nuniform float backgroundIntensity;\nvarying vec2 vUv...
vertex$g "varying vec3 vWorldDirection;\n#incl... let/var "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDir...
fragment$g "#ifdef ENVMAP_TYPE_CUBE\n\tuniform s... let/var "#ifdef ENVMAP_TYPE_CUBE\n\tuniform samplerCube envMap;\n#elif defined( ENVMA...
vertex$f "varying vec3 vWorldDirection;\n#incl... let/var "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDir...
fragment$f "uniform samplerCube tCube;\nuniform ... let/var "uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nva...
vertex$e "#include <common>\n#include <batchin... let/var "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex...
fragment$e "#if DEPTH_PACKING == 3200\n\tuniform... let/var "#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include <commo...
vertex$d "#define DISTANCE\nvarying vec3 vWorl... let/var "#define DISTANCE\nvarying vec3 vWorldPosition;\n#include <common>\n#include ...
fragment$d "#define DISTANCE\nuniform vec3 refer... let/var "#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistanc...
vertex$c "varying vec3 vWorldDirection;\n#incl... let/var "varying vec3 vWorldDirection;\n#include <common>\nvoid main() {\n\tvWorldDir...
fragment$c "uniform sampler2D tEquirect;\nvaryin... let/var "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include <commo...
vertex$b "uniform float scale;\nattribute floa... let/var "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDist...
fragment$b "uniform vec3 diffuse;\nuniform float... let/var "uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nunif...
vertex$a "#include <common>\n#include <batchin... let/var "#include <common>\n#include <batching_pars_vertex>\n#include <uv_pars_vertex...
fragment$a "uniform vec3 diffuse;\nuniform float... let/var "uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvaryin...
vertex$9 "#define LAMBERT\nvarying vec3 vViewP... let/var "#define LAMBERT\nvarying vec3 vViewPosition;\n#include <common>\n#include <b...
fragment$9 "#define LAMBERT\nuniform vec3 diffus... let/var "#define LAMBERT\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform floa...
vertex$8 "#define MATCAP\nvarying vec3 vViewPo... let/var "#define MATCAP\nvarying vec3 vViewPosition;\n#include <common>\n#include <ba...
fragment$8 "#define MATCAP\nuniform vec3 diffuse... let/var "#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampl...
vertex$7 "#define NORMAL\n#if defined( FLAT_SH... let/var "#define NORMAL\n#if defined( FLAT_SHADED ) \|\| defined( USE_BUMPMAP ) \|\| ...
fragment$7 "#define NORMAL\nuniform float opacit... let/var "#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) \|\| defi...
vertex$6 "#define PHONG\nvarying vec3 vViewPos... let/var "#define PHONG\nvarying vec3 vViewPosition;\n#include <common>\n#include <bat...
fragment$6 "#define PHONG\nuniform vec3 diffuse;... let/var "#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 s...
vertex$5 "#define STANDARD\nvarying vec3 vView... let/var "#define STANDARD\nvarying vec3 vViewPosition;\n#ifdef USE_TRANSMISSION\n\tva...
fragment$5 "#define STANDARD\n#ifdef PHYSICAL\n\... let/var "#define STANDARD\n#ifdef PHYSICAL\n\t#define IOR\n\t#define USE_SPECULAR\n#e...
vertex$4 "#define TOON\nvarying vec3 vViewPosi... let/var "#define TOON\nvarying vec3 vViewPosition;\n#include <common>\n#include <batc...
fragment$4 "#define TOON\nuniform vec3 diffuse;\... let/var "#define TOON\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float o...
vertex$3 "uniform float size;\nuniform float s... let/var "uniform float size;\nuniform float scale;\n#include <common>\n#include <colo...
fragment$3 "uniform vec3 diffuse;\nuniform float... let/var "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <...
vertex$2 "#include <common>\n#include <batchin... let/var "#include <common>\n#include <batching_pars_vertex>\n#include <fog_pars_verte...
fragment$2 "uniform vec3 color;\nuniform float o... let/var "uniform vec3 color;\nuniform float opacity;\n#include <common>\n#include <pa...
vertex$1 "uniform float rotation;\nuniform vec... let/var "uniform float rotation;\nuniform vec2 center;\n#include <common>\n#include <...
fragment$1 "uniform vec3 diffuse;\nuniform float... let/var "uniform vec3 diffuse;\nuniform float opacity;\n#include <common>\n#include <...
ShaderChunk { alphahash_fragment: string; alphaha... let/var { alphahash_fragment: alphahash_fragment, alphahash_pars_fragment: alphahash_...
UniformsLib { common: { diffuse: { value: Color; ... let/var { common: { diffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) }, opacity:...
ShaderLib { basic: { uniforms: {}; vertexShader... let/var { basic: { uniforms: /*@__PURE__*/ mergeUniforms( [ UniformsLib.common, Unifo...
_rgb { r: number; b: number; g: number; } let/var { r: 0, b: 0, g: 0 }
_e1$1 Euler let/var new Euler()
_m1$1 Matrix4 let/var new Matrix4()
clearColor Color let/var new Color( 0x000000 )
clearAlpha number let/var alpha === true ? 0 : 1
planeMesh any let/var *not shown*
boxMesh any let/var *not shown*
currentBackground any let/var null
currentBackgroundVersion number let/var 0
currentTonemapping any let/var null
background any let/var scene.isScene === true ? scene.background : null
usePMREM boolean let/var scene.backgroundBlurriness > 0
forceClear boolean let/var false
bindingStates {} let/var {}
currentState { geometry: any; program: any; wirefr... let/var defaultState
forceUpdate boolean let/var false
updateBuffers boolean let/var false
wireframe boolean let/var ( material.wireframe === true )
programMap any let/var bindingStates[ geometry.id ]
stateMap any let/var programMap[ program.id ]
state any let/var stateMap[ wireframe ]
newAttributes any[] let/var []
enabledAttributes any[] let/var []
attributeDivisors any[] let/var []
cachedAttributes {} let/var currentState.attributes
geometryAttributes any let/var geometry.attributes
attributesNum number let/var 0
programAttribute any let/var programAttributes[ name ]
cachedAttribute any let/var cachedAttributes[ name ]
geometryAttribute any let/var geometryAttributes[ name ]
cache {} let/var {}
attributes any let/var geometry.attributes
attributesNum number let/var 0
programAttribute any let/var programAttributes[ name ]
attribute any let/var attributes[ name ]
data { attribute: any; } let/var {}
newAttributes number[] let/var currentState.newAttributes
newAttributes number[] let/var currentState.newAttributes
enabledAttributes number[] let/var currentState.enabledAttributes
attributeDivisors number[] let/var currentState.attributeDivisors
newAttributes number[] let/var currentState.newAttributes
enabledAttributes number[] let/var currentState.enabledAttributes
geometryAttributes any let/var geometry.attributes
materialDefaultAttributeValues any let/var material.defaultAttributeValues
programAttribute any let/var programAttributes[ name ]
geometryAttribute any let/var geometryAttributes[ name ]
normalized any let/var geometryAttribute.normalized
size any let/var geometryAttribute.itemSize
buffer any let/var attribute.buffer
type any let/var attribute.type
bytesPerElement any let/var attribute.bytesPerElement
integer boolean let/var ( type === gl.INT \|\| type === gl.UNSIGNED_INT \|\| geometryAttribute.gpuTyp...
data any let/var geometryAttribute.data
stride any let/var data.stride
offset any let/var geometryAttribute.offset
value any let/var materialDefaultAttributeValues[ name ]
programMap any let/var bindingStates[ geometryId ]
stateMap any let/var programMap[ programId ]
programMap any let/var bindingStates[ geometry.id ]
stateMap any let/var programMap[ programId ]
programMap any let/var bindingStates[ geometryId ]
stateMap any let/var programMap[ program.id ]
mode any let/var *not shown*
elementCount number let/var 0
elementCount number let/var 0
maxAnisotropy any let/var *not shown*
halfFloatSupportedByExt any let/var ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half...
precision any let/var parameters.precision !== undefined ? parameters.precision : 'highp'
logarithmicDepthBuffer boolean let/var parameters.logarithmicDepthBuffer === true
reversedDepthBuffer any let/var parameters.reversedDepthBuffer === true && extensions.has( 'EXT_clip_control' )
vertexTextures boolean let/var maxVertexTextures > 0
scope this let/var this
globalState any let/var null
numGlobalPlanes number let/var 0
localClippingEnabled boolean let/var false
renderingShadows boolean let/var false
plane Plane let/var new Plane()
viewNormalMatrix Matrix3 let/var new Matrix3()
uniform { value: any; needsUpdate: boolean; } let/var { value: null, needsUpdate: false }
enabled any let/var planes.length !== 0 \|\| enableLocalClipping \|\| // enable state of previous...
planes any let/var material.clippingPlanes
clipIntersection any let/var material.clipIntersection
clipShadows any let/var material.clipShadows
nGlobal number let/var renderingShadows ? 0 : numGlobalPlanes
lGlobal number let/var nGlobal * 4
dstArray any let/var materialProperties.clippingState \|\| null
nPlanes any let/var planes !== null ? planes.length : 0
dstArray any let/var null
flatSize any let/var dstOffset + nPlanes * 4
viewMatrix any let/var camera.matrixWorldInverse
cubemaps WeakMap<WeakKey, any> let/var new WeakMap()
mapping any let/var texture.mapping
cubemap any let/var cubemaps.get( texture ).texture
image any let/var texture.image
renderTarget WebGLCubeRenderTarget let/var new WebGLCubeRenderTarget( image.height )
texture any let/var event.target
LOD_MIN 4 let/var 4
EXTRA_LOD_SIGMA number[] let/var [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ]
MAX_SAMPLES 20 let/var 20
_flatCamera OrthographicCamera let/var new OrthographicCamera()
_clearColor Color let/var new Color()
_oldTarget any let/var null
_oldActiveCubeFace number let/var 0
_oldActiveMipmapLevel number let/var 0
_oldXrEnabled boolean let/var false
PHI number let/var ( 1 + Math.sqrt( 5 ) ) / 2
INV_PHI number let/var 1 / PHI
_axisDirections Vector3[] let/var [ /*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ), /*@__PURE__*/ new Vector3( ...
_origin Vector3 let/var new Vector3()
cubeUVRenderTarget any let/var renderTarget \|\| this._allocateTargets()
width number let/var 3 * Math.max( this._cubeSize, 16 * 7 )
height number let/var 4 * this._cubeSize
params { magFilter: number; minFilter: numbe... let/var { magFilter: LinearFilter, minFilter: LinearFilter, generateMipmaps: false, t...
tmpMesh Mesh let/var new Mesh( this._lodPlanes[ 0 ], material )
fov 90 let/var 90
aspect 1 let/var 1
cubeCamera PerspectiveCamera let/var new PerspectiveCamera( fov, aspect, near, far )
upSign number[] let/var [ 1, -1, 1, 1, 1, 1 ]
forwardSign number[] let/var [ 1, 1, 1, -1, -1, -1 ]
renderer WebGLRenderer let/var this._renderer
originalAutoClear boolean let/var renderer.autoClear
toneMapping number let/var renderer.toneMapping
backgroundMaterial MeshBasicMaterial let/var new MeshBasicMaterial( { name: 'PMREM.Background', side: BackSide, depthWrite...
backgroundBox Mesh let/var new Mesh( new BoxGeometry(), backgroundMaterial )
useSolidColor boolean let/var false
background any let/var scene.background
col number let/var i % 3
size number let/var this._cubeSize
renderer WebGLRenderer let/var this._renderer
isCubeTexture boolean let/var ( texture.mapping === CubeReflectionMapping \|\| texture.mapping === CubeRefr...
material ShaderMaterial let/var isCubeTexture ? this._cubemapMaterial : this._equirectMaterial
mesh Mesh let/var new Mesh( this._lodPlanes[ 0 ], material )
uniforms any let/var material.uniforms
size number let/var this._cubeSize
renderer WebGLRenderer let/var this._renderer
autoClear boolean let/var renderer.autoClear
n number let/var this._lodPlanes.length
poleAxis Vector3 let/var _axisDirections[ ( n - i - 1 ) % _axisDirections.length ]
pingPongRenderTarget WebGLRenderTarget let/var this._pingPongRenderTarget
renderer WebGLRenderer let/var this._renderer
blurMaterial ShaderMaterial let/var this._blurMaterial
STANDARD_DEVIATIONS 3 let/var 3
blurMesh Mesh let/var new Mesh( this._lodPlanes[ lodOut ], blurMaterial )
blurUniforms any let/var blurMaterial.uniforms
pixels number let/var this._sizeLods[ lodIn ] - 1
radiansPerPixel number let/var isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX...
sigmaPixels number let/var sigmaRadians / radiansPerPixel
samples number let/var isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ...
weights any[] let/var []
sum number let/var 0
x number let/var i / sigmaPixels
outputSize any let/var this._sizeLods[ lodOut ]
x number let/var 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 )
y number let/var 4 * ( this._cubeSize - outputSize )
lodPlanes any[] let/var []
sizeLods any[] let/var []
sigmas any[] let/var []
lod any let/var lodMax
totalLods number let/var lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length
sigma number let/var 1.0 / sizeLod
texelSize number let/var 1.0 / ( sizeLod - 2 )
min number let/var - texelSize
max number let/var 1 + texelSize
uv1 number[] let/var [ min, min, max, min, max, max, min, min, max, max, min, max ]
cubeFaces 6 let/var 6
vertices 6 let/var 6
positionSize 3 let/var 3
uvSize 2 let/var 2
faceIndexSize 1 let/var 1
position Float32Array<ArrayBuffer> let/var new Float32Array( positionSize * vertices * cubeFaces )
uv Float32Array<ArrayBuffer> let/var new Float32Array( uvSize * vertices * cubeFaces )
faceIndex Float32Array<ArrayBuffer> let/var new Float32Array( faceIndexSize * vertices * cubeFaces )
x number let/var ( face % 3 ) * 2 / 3 - 1
y 0 \| -1 let/var face > 2 ? 0 : -1
coordinates number[] let/var [ x, y, 0, x + 2 / 3, y, 0, x + 2 / 3, y + 1, 0, x, y, 0, x + 2 / 3, y + 1, 0...
fill number[] let/var [ face, face, face, face, face, face ]
planes BufferGeometry let/var new BufferGeometry()
cubeUVRenderTarget WebGLRenderTarget let/var new WebGLRenderTarget( width, height, params )
weights Float32Array<ArrayBuffer> let/var new Float32Array( MAX_SAMPLES )
poleAxis Vector3 let/var new Vector3( 0, 1, 0 )
shaderMaterial ShaderMaterial let/var new ShaderMaterial( { name: 'SphericalGaussianBlur', defines: { 'n': MAX_SAMP...
cubeUVmaps WeakMap<WeakKey, any> let/var new WeakMap()
pmremGenerator any let/var null
mapping any let/var texture.mapping
isEquirectMap boolean let/var ( mapping === EquirectangularReflectionMapping \|\| mapping === Equirectangul...
isCubeMap boolean let/var ( mapping === CubeReflectionMapping \|\| mapping === CubeRefractionMapping )
currentPMREMVersion any let/var renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0
image any let/var texture.image
count number let/var 0
length 6 let/var 6
texture any let/var event.target
extensions {} let/var {}
extension any let/var *not shown*
geometries {} let/var {}
wireframeAttributes WeakMap<WeakKey, any> let/var new WeakMap()
geometry any let/var event.target
geometryAttributes any let/var geometry.attributes
indices any[] let/var []
geometryIndex any let/var geometry.index
geometryPosition any let/var geometry.attributes.position
version number let/var 0
array any let/var geometryIndex.array
a any let/var array[ i + 0 ]
b any let/var array[ i + 1 ]
c any let/var array[ i + 2 ]
array any let/var geometryPosition.array
a number let/var i + 0
b number let/var i + 1
c number let/var i + 2
attribute Uint32BufferAttribute \| Uint16Buffer... let/var new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttri...
geometryIndex any let/var geometry.index
mode any let/var *not shown*
type any let/var *not shown*
bytesPerElement any let/var *not shown*
elementCount number let/var 0
elementCount number let/var 0
memory { geometries: number; textures: numbe... let/var { geometries: 0, textures: 0 }
render { frame: number; calls: number; trian... let/var { frame: 0, calls: 0, triangles: 0, points: 0, lines: 0 }
morphTextures WeakMap<WeakKey, any> let/var new WeakMap()
morph Vector4 let/var new Vector4()
objectInfluences any let/var object.morphTargetInfluences
morphAttribute any let/var geometry.morphAttributes.position \|\| geometry.morphAttributes.normal \|\| g...
morphTargetsCount any let/var ( morphAttribute !== undefined ) ? morphAttribute.length : 0
hasMorphPosition boolean let/var geometry.morphAttributes.position !== undefined
hasMorphNormals boolean let/var geometry.morphAttributes.normal !== undefined
hasMorphColors boolean let/var geometry.morphAttributes.color !== undefined
morphTargets any let/var geometry.morphAttributes.position \|\| []
morphNormals any let/var geometry.morphAttributes.normal \|\| []
morphColors any let/var geometry.morphAttributes.color \|\| []
vertexDataCount number let/var 0
width number let/var geometry.attributes.position.count * vertexDataCount
height number let/var 1
buffer Float32Array<ArrayBuffer> let/var new Float32Array( width * height * 4 * morphTargetsCount )
texture DataArrayTexture let/var new DataArrayTexture( buffer, width, height, morphTargetsCount )
vertexDataStride number let/var vertexDataCount * 4
morphTarget any let/var morphTargets[ i ]
morphNormal any let/var morphNormals[ i ]
morphColor any let/var morphColors[ i ]
offset number let/var width * height * 4 * i
stride number let/var j * vertexDataStride
morphInfluencesSum number let/var 0
morphBaseInfluence number let/var geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum
updateMap WeakMap<WeakKey, any> let/var new WeakMap()
frame any let/var info.render.frame
geometry any let/var object.geometry
skeleton any let/var object.skeleton
instancedMesh any let/var event.target
emptyTexture Texture let/var new Texture()
emptyShadowTexture DepthTexture let/var new DepthTexture( 1, 1 )
emptyArrayTexture DataArrayTexture let/var new DataArrayTexture()
empty3dTexture Data3DTexture let/var new Data3DTexture()
emptyCubeTexture CubeTexture let/var new CubeTexture()
arrayCacheF32 any[] let/var []
arrayCacheI32 any[] let/var []
mat4array Float32Array<ArrayBuffer> let/var new Float32Array( 16 )
mat3array Float32Array<ArrayBuffer> let/var new Float32Array( 9 )
mat2array Float32Array<ArrayBuffer> let/var new Float32Array( 4 )
firstElem any let/var array[ 0 ]
n number let/var nBlocks * blockSize
r any let/var arrayCacheF32[ n ]
r any let/var arrayCacheI32[ n ]
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
elements any let/var v.elements
cache any let/var this.cache
elements any let/var v.elements
cache any let/var this.cache
elements any let/var v.elements
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
emptyTexture2D any let/var *not shown*
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
cache any let/var this.cache
n any let/var v.length
cache any let/var this.cache
n any let/var v.length
cache any let/var this.cache
n any let/var v.length
cache any let/var this.cache
n any let/var v.length
seq any[] let/var this.seq
u any let/var seq[ i ]
RePathPart RegExp let/var /(\w+)(\])?(\[\|\.)?/g
path any let/var activeInfo.name
pathLength any let/var path.length
matchEnd number let/var RePathPart.lastIndex
id string let/var match[ 1 ]
idIsIndex boolean let/var match[ 2 ] === ']'
subscript string let/var match[ 3 ]
map any let/var container.map
next any let/var map[ id ]
u any let/var this.map[ name ]
v any let/var object[ name ]
u any let/var seq[ i ]
v any let/var values[ u.id ]
r any[] let/var []
u any let/var seq[ i ]
COMPLETION_STATUS_KHR 37297 let/var 0x91B1
programIdCount number let/var 0
lines2 any[] let/var []
line number let/var i + 1
_m0 Matrix3 let/var new Matrix3()
encodingMatrix string let/var mat3( ${ _m0.elements.map( ( v ) => v.toFixed( 4 ) ) } )
shaderInfoLog any let/var gl.getShaderInfoLog( shader ) \|\| ''
toneMappingName any let/var *not shown*
_v0 Vector3 let/var new Vector3()
chunks string[] let/var [ parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_dista...
chunks any[] let/var []
value any let/var defines[ name ]
attributes {} let/var {}
name any let/var info.name
locationSize number let/var 1
numSpotLightCoords number let/var parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.num...
includePattern RegExp let/var /^[ \t]*#include +<([\w\d./]+)>/gm
shaderChunkMap Map<any, any> let/var new Map()
string any let/var ShaderChunk[ include ]
unrollLoopPattern RegExp let/var /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d...
string string let/var ''
precisionstring string let/var `precision ${parameters.precision} float; precision ${parameters.precision} i...
shadowMapTypeDefine string let/var 'SHADOWMAP_TYPE_BASIC'
envMapTypeDefine string let/var 'ENVMAP_TYPE_CUBE'
envMapModeDefine string let/var 'ENVMAP_MODE_REFLECTION'
envMapBlendingDefine string let/var 'ENVMAP_BLENDING_NONE'
imageHeight any let/var parameters.envMapCubeUVHeight
maxMip number let/var Math.log2( imageHeight ) - 2
texelHeight number let/var 1.0 / imageHeight
texelWidth number let/var 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) )
defines any let/var parameters.defines
vertexShader any let/var parameters.vertexShader
fragmentShader any let/var parameters.fragmentShader
prefixVertex any let/var *not shown*
prefixFragment any let/var *not shown*
versionString string let/var parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : ''
vertexGlsl string let/var versionString + prefixVertex + vertexShader
fragmentGlsl string let/var versionString + prefixFragment + fragmentShader
programInfoLog any let/var gl.getProgramInfoLog( program ) \|\| ''
vertexShaderInfoLog any let/var gl.getShaderInfoLog( glVertexShader ) \|\| ''
fragmentShaderInfoLog any let/var gl.getShaderInfoLog( glFragmentShader ) \|\| ''
runnable boolean let/var true
haveDiagnostics boolean let/var true
cachedUniforms any let/var *not shown*
cachedAttributes any let/var *not shown*
programReady boolean let/var ( parameters.rendererExtensionParallelShaderCompile === false )
_id number let/var 0
vertexShader any let/var material.vertexShader
fragmentShader any let/var material.fragmentShader
cache Map<any, any> let/var this.materialCache
cache Map<any, any> let/var this.shaderCache
_programLayers Layers let/var new Layers()
_customShaders WebGLShaderCache let/var new WebGLShaderCache()
_activeChannels Set<any> let/var new Set()
programs any[] let/var []
logarithmicDepthBuffer any let/var capabilities.logarithmicDepthBuffer
SUPPORTS_VERTEX_TEXTURES any let/var capabilities.vertexTextures
precision any let/var capabilities.precision
shaderIDs { MeshDepthMaterial: string; MeshDist... let/var { MeshDepthMaterial: 'depth', MeshDistanceMaterial: 'distanceRGBA', MeshNorma...
fog any let/var scene.fog
geometry any let/var object.geometry
environment any let/var material.isMeshStandardMaterial ? scene.environment : null
envMapCubeUVHeight any let/var ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.imag...
shaderID any let/var shaderIDs[ material.type ]
morphAttribute any let/var geometry.morphAttributes.position \|\| geometry.morphAttributes.normal \|\| g...
morphTargetsCount any let/var ( morphAttribute !== undefined ) ? morphAttribute.length : 0
morphTextureStride number let/var 0
vertexShader any let/var *not shown*
fragmentShader any let/var *not shown*
customVertexShaderID any let/var *not shown*
customFragmentShaderID any let/var *not shown*
shader any let/var ShaderLib[ shaderID ]
IS_INSTANCEDMESH boolean let/var object.isInstancedMesh === true
IS_BATCHEDMESH boolean let/var object.isBatchedMesh === true
HAS_MAP boolean let/var !! material.map
HAS_MATCAP boolean let/var !! material.matcap
HAS_ENVMAP boolean let/var !! envMap
HAS_AOMAP boolean let/var !! material.aoMap
HAS_LIGHTMAP boolean let/var !! material.lightMap
HAS_BUMPMAP boolean let/var !! material.bumpMap
HAS_NORMALMAP boolean let/var !! material.normalMap
HAS_DISPLACEMENTMAP boolean let/var !! material.displacementMap
HAS_EMISSIVEMAP boolean let/var !! material.emissiveMap
HAS_METALNESSMAP boolean let/var !! material.metalnessMap
HAS_ROUGHNESSMAP boolean let/var !! material.roughnessMap
HAS_ANISOTROPY boolean let/var material.anisotropy > 0
HAS_CLEARCOAT boolean let/var material.clearcoat > 0
HAS_DISPERSION boolean let/var material.dispersion > 0
HAS_IRIDESCENCE boolean let/var material.iridescence > 0
HAS_SHEEN boolean let/var material.sheen > 0
HAS_TRANSMISSION boolean let/var material.transmission > 0
HAS_ANISOTROPYMAP boolean let/var HAS_ANISOTROPY && !! material.anisotropyMap
HAS_CLEARCOATMAP boolean let/var HAS_CLEARCOAT && !! material.clearcoatMap
HAS_CLEARCOAT_NORMALMAP boolean let/var HAS_CLEARCOAT && !! material.clearcoatNormalMap
HAS_CLEARCOAT_ROUGHNESSMAP boolean let/var HAS_CLEARCOAT && !! material.clearcoatRoughnessMap
HAS_IRIDESCENCEMAP boolean let/var HAS_IRIDESCENCE && !! material.iridescenceMap
HAS_IRIDESCENCE_THICKNESSMAP boolean let/var HAS_IRIDESCENCE && !! material.iridescenceThicknessMap
HAS_SHEEN_COLORMAP boolean let/var HAS_SHEEN && !! material.sheenColorMap
HAS_SHEEN_ROUGHNESSMAP boolean let/var HAS_SHEEN && !! material.sheenRoughnessMap
HAS_SPECULARMAP boolean let/var !! material.specularMap
HAS_SPECULAR_COLORMAP boolean let/var !! material.specularColorMap
HAS_SPECULAR_INTENSITYMAP boolean let/var !! material.specularIntensityMap
HAS_TRANSMISSIONMAP boolean let/var HAS_TRANSMISSION && !! material.transmissionMap
HAS_THICKNESSMAP boolean let/var HAS_TRANSMISSION && !! material.thicknessMap
HAS_GRADIENTMAP boolean let/var !! material.gradientMap
HAS_ALPHAMAP boolean let/var !! material.alphaMap
HAS_ALPHATEST boolean let/var material.alphaTest > 0
HAS_ALPHAHASH boolean let/var !! material.alphaHash
HAS_EXTENSIONS boolean let/var !! material.extensions
toneMapping number let/var NoToneMapping
parameters { shaderID: any; shaderType: any; sha... let/var { shaderID: shaderID, shaderType: material.type, shaderName: material.name, v...
array any[] let/var []
shaderID any let/var shaderIDs[ material.type ]
uniforms any let/var *not shown*
shader any let/var ShaderLib[ shaderID ]
program any let/var *not shown*
preexistingProgram any let/var programs[ p ]
properties WeakMap<WeakKey, any> let/var new WeakMap()
renderItems any[] let/var []
renderItemsIndex number let/var 0
opaque any[] let/var []
transmissive any[] let/var []
transparent any[] let/var []
renderItem any let/var renderItems[ renderItemsIndex ]
renderItem any let/var renderItems[ i ]
lists WeakMap<WeakKey, any> let/var new WeakMap()
list any let/var *not shown*
lights {} let/var {}
uniforms any let/var *not shown*
lights {} let/var {}
uniforms any let/var *not shown*
nextVersion number let/var 0
cache any let/var new UniformsCache()
state { version: number; hash: { directiona... let/var { version: 0, hash: { directionalLength: -1, pointLength: -1, spotLength: -1,...
vector3 Vector3 let/var new Vector3()
matrix4 Matrix4 let/var new Matrix4()
matrix42 Matrix4 let/var new Matrix4()
r number let/var 0
g number let/var 0
b number let/var 0
directionalLength number let/var 0
pointLength number let/var 0
spotLength number let/var 0
rectAreaLength number let/var 0
hemiLength number let/var 0
numDirectionalShadows number let/var 0
numPointShadows number let/var 0
numSpotShadows number let/var 0
numSpotMaps number let/var 0
numSpotShadowsWithMaps number let/var 0
numLightProbes number let/var 0
light any let/var lights[ i ]
color any let/var light.color
intensity any let/var light.intensity
distance any let/var light.distance
shadowMap any let/var ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null
shadow any let/var light.shadow
shadow any let/var light.shadow
shadow any let/var light.shadow
hash { directionalLength: number; pointLen... let/var state.hash
directionalLength number let/var 0
pointLength number let/var 0
spotLength number let/var 0
rectAreaLength number let/var 0
hemiLength number let/var 0
viewMatrix any let/var camera.matrixWorldInverse
light any let/var lights[ i ]
uniforms any let/var state.directional[ directionalLength ]
uniforms any let/var state.spot[ spotLength ]
uniforms any let/var state.rectArea[ rectAreaLength ]
uniforms any let/var state.point[ pointLength ]
uniforms any let/var state.hemi[ hemiLength ]
lights any let/var new WebGLLights( extensions )
lightsArray any[] let/var []
shadowsArray any[] let/var []
state { lightsArray: any[]; shadowsArray: a... let/var { lightsArray: lightsArray, shadowsArray: shadowsArray, camera: null, lights:...
renderStates WeakMap<WeakKey, any> let/var new WeakMap()
renderState any let/var *not shown*
vertex "void main() {\n\tgl_Position = vec4(... let/var "void main() {\n\tgl_Position = vec4( position, 1.0 );\n}"
fragment "uniform sampler2D shadow_pass;\nunif... let/var "uniform sampler2D shadow_pass;\nuniform vec2 resolution;\nuniform float radi...
_frustum Frustum let/var new Frustum()
_shadowMapSize Vector2 let/var new Vector2()
_viewportSize Vector2 let/var new Vector2()
_viewport Vector4 let/var new Vector4()
_depthMaterial MeshDepthMaterial let/var new MeshDepthMaterial( { depthPacking: RGBADepthPacking } )
_distanceMaterial MeshDistanceMaterial let/var new MeshDistanceMaterial()
_materialCache {} let/var {}
_maxTextureSize any let/var capabilities.maxTextureSize
shadowSide { [x: number]: number; } let/var { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide }
shadowMaterialVertical ShaderMaterial let/var new ShaderMaterial( { defines: { VSM_SAMPLES: 8 }, uniforms: { shadow_pass: {...
fullScreenTri BufferGeometry let/var new BufferGeometry()
fullScreenMesh Mesh let/var new Mesh( fullScreenTri, shadowMaterialVertical )
scope this let/var this
_previousType number let/var this.type
_state any let/var renderer.state
toVSM boolean let/var ( _previousType !== VSMShadowMap && this.type === VSMShadowMap )
fromVSM boolean let/var ( _previousType === VSMShadowMap && this.type !== VSMShadowMap )
light any let/var lights[ i ]
shadow any let/var light.shadow
pars { minFilter: number; magFilter: numbe... let/var ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: Neare...
result any let/var null
customMaterial any let/var ( light.isPointLight === true ) ? object.customDistanceMaterial : object.cust...
keyA string let/var result.uuid
keyB any let/var material.uuid
materialsForVariant any let/var _materialCache[ keyA ]
cachedMaterial any let/var materialsForVariant[ keyB ]
material any let/var object.material
groups any let/var geometry.groups
group any let/var groups[ k ]
groupMaterial any let/var material[ group.materialIndex ]
children any let/var object.children
material any let/var event.target
cache any let/var _materialCache[ id ]
uuid any let/var event.target.uuid
shadowMaterial any let/var cache[ uuid ]
reversedFuncs { [x: number]: number; } let/var { [ NeverDepth ]: AlwaysDepth, [ LessDepth ]: GreaterDepth, [ EqualDepth ]: N...
locked boolean let/var false
color Vector4 let/var new Vector4()
currentColorMask any let/var null
currentColorClear Vector4 let/var new Vector4( 0, 0, 0, 0 )
locked boolean let/var false
currentReversed boolean let/var false
currentDepthMask any let/var null
currentDepthFunc any let/var null
currentDepthClear any let/var null
oldDepth any let/var currentDepthClear
locked boolean let/var false
currentStencilMask any let/var null
currentStencilFunc any let/var null
currentStencilRef any let/var null
currentStencilFuncMask any let/var null
currentStencilFail any let/var null
currentStencilZFail any let/var null
currentStencilZPass any let/var null
currentStencilClear any let/var null
colorBuffer any let/var new ColorBuffer()
depthBuffer any let/var new DepthBuffer()
stencilBuffer any let/var new StencilBuffer()
uboBindings WeakMap<WeakKey, any> let/var new WeakMap()
uboProgramMap WeakMap<WeakKey, any> let/var new WeakMap()
enabledCapabilities {} let/var {}
currentBoundFramebuffers {} let/var {}
currentDrawbuffers WeakMap<WeakKey, any> let/var new WeakMap()
defaultDrawbuffers any[] let/var []
currentProgram any let/var null
currentBlendingEnabled boolean let/var false
currentBlending any let/var null
currentBlendEquation any let/var null
currentBlendSrc any let/var null
currentBlendDst any let/var null
currentBlendEquationAlpha any let/var null
currentBlendSrcAlpha any let/var null
currentBlendDstAlpha any let/var null
currentBlendColor Color let/var new Color( 0, 0, 0 )
currentBlendAlpha number let/var 0
currentPremultipledAlpha boolean let/var false
currentFlipSided any let/var null
currentCullFace any let/var null
currentLineWidth any let/var null
currentPolygonOffsetFactor any let/var null
currentPolygonOffsetUnits any let/var null
lineWidthAvailable boolean let/var false
version number let/var 0
currentTextureSlot any let/var null
currentBoundTextures {} let/var {}
data Uint8Array<ArrayBuffer> let/var new Uint8Array( 4 )
emptyTextures {} let/var {}
drawBuffers any[] let/var defaultDrawbuffers
needsUpdate boolean let/var false
textures any let/var renderTarget.textures
equationToGL { [x: number]: any; } let/var { [ AddEquation ]: gl.FUNC_ADD, [ SubtractEquation ]: gl.FUNC_SUBTRACT, [ Rev...
factorToGL { [x: number]: any; } let/var { [ ZeroFactor ]: gl.ZERO, [ OneFactor ]: gl.ONE, [ SrcColorFactor ]: gl.SRC_...
flipSided boolean let/var ( material.side === BackSide )
stencilWrite any let/var material.stencilWrite
boundTexture any let/var currentBoundTextures[ webglSlot ]
boundTexture any let/var currentBoundTextures[ currentTextureSlot ]
multisampledRTTExt any let/var extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'W...
supportsInvalidateFramebuffer boolean let/var typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.u...
_imageDimensions Vector2 let/var new Vector2()
_videoTextures WeakMap<WeakKey, any> let/var new WeakMap()
_canvas any let/var *not shown*
_sources WeakMap<WeakKey, any> let/var new WeakMap()
useOffscreenCanvas boolean let/var false
scale number let/var 1
canvas any let/var needsNewCanvas ? createCanvas( width, height ) : _canvas
internalFormat any let/var glFormat
transfer any let/var forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace )
glInternalFormat any let/var *not shown*
texture any let/var event.target
renderTarget any let/var event.target
source any let/var texture.source
webglTexture any let/var webglTextures[ textureProperties.__cacheKey ]
source any let/var texture.source
textures any let/var renderTarget.textures
textureUnits number let/var 0
textureUnit number let/var textureUnits
array any[] let/var []
image any let/var texture.image
wrappingToGL { [x: number]: any; } let/var { [ RepeatWrapping ]: _gl.REPEAT, [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,...
filterToGL { [x: number]: any; } let/var { [ NearestFilter ]: _gl.NEAREST, [ NearestMipmapNearestFilter ]: _gl.NEAREST...
compareToGL { [x: number]: any; } let/var { [ NeverCompare ]: _gl.NEVER, [ AlwaysCompare ]: _gl.ALWAYS, [ LessCompare ]...
forceUpload boolean let/var false
source any let/var texture.source
webglTexture any let/var webglTextures[ textureProperties.__cacheKey ]
componentStride 4 let/var 4
updateRanges any let/var texture.updateRanges
mergeIndex number let/var 0
previousRange any let/var updateRanges[ mergeIndex ]
range any let/var updateRanges[ i ]
previousEnd any let/var previousRange.start + previousRange.count
range any let/var updateRanges[ i ]
x number let/var pixelStart % image.width
width number let/var pixelCount
height 1 let/var 1
textureType any let/var _gl.TEXTURE_2D
source any let/var texture.source
texturePrimaries any let/var texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( te...
unpackConversion any let/var texture.colorSpace === NoColorSpace \|\| workingPrimaries === texturePrimarie...
mipmap any let/var *not shown*
mipmaps any let/var texture.mipmaps
useTexStorage boolean let/var ( texture.isVideoTexture !== true )
allocateMemory boolean let/var ( sourceProperties.__version === undefined ) \|\| ( forceUpload === true )
dataReady any let/var source.dataReady
width any let/var image.width
height any let/var image.height
source any let/var texture.source
texturePrimaries any let/var texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( te...
unpackConversion any let/var texture.colorSpace === NoColorSpace \|\| workingPrimaries === texturePrimarie...
isCompressed any let/var ( texture.isCompressedTexture \|\| texture.image[ 0 ].isCompressedTexture )
isDataTexture any let/var ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture )
cubeImage any[] let/var []
image any let/var cubeImage[ 0 ]
useTexStorage boolean let/var ( texture.isVideoTexture !== true )
allocateMemory boolean let/var ( sourceProperties.__version === undefined ) \|\| ( forceUpload === true )
dataReady any let/var source.dataReady
mipmaps any let/var *not shown*
mipmap any let/var mipmaps[ j ]
mipmap any let/var mipmaps[ j ]
mipmapImage any let/var mipmap.image[ i ].image
mipmap any let/var mipmaps[ j ]
depthTexture any let/var renderTarget.depthTexture
depthType any let/var depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null
glAttachmentType any let/var renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT
textures any let/var renderTarget.textures
texture any let/var textures[ i ]
isCube any let/var ( renderTarget && renderTarget.isWebGLCubeRenderTarget )
webglDepthTexture any let/var textureProperties.__webglTexture
isCube boolean let/var ( renderTarget.isWebGLCubeRenderTarget === true )
depthTexture any let/var renderTarget.depthTexture
mipmaps any let/var renderTarget.texture.mipmaps
glAttachmentType any let/var renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT
renderbuffer any let/var renderTargetProperties.__webglDepthbuffer[ i ]
mipmaps any let/var renderTarget.texture.mipmaps
glAttachmentType any let/var renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT
renderbuffer any let/var renderTargetProperties.__webglDepthbuffer
texture any let/var renderTarget.texture
textures any let/var renderTarget.textures
isCube boolean let/var ( renderTarget.isWebGLCubeRenderTarget === true )
isMultipleRenderTargets boolean let/var ( textures.length > 1 )
texture any let/var textures[ i ]
attachment any let/var textures[ i ]
glTextureType any let/var _gl.TEXTURE_2D
glTextureType any let/var _gl.TEXTURE_2D
textures any let/var renderTarget.textures
texture any let/var textures[ i ]
webglTexture any let/var properties.get( texture ).__webglTexture
invalidationArrayRead any[] let/var []
invalidationArrayDraw any[] let/var []
textures any let/var renderTarget.textures
width any let/var renderTarget.width
height any let/var renderTarget.height
mask any let/var _gl.COLOR_BUFFER_BIT
depthStyle any let/var renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT
isMultipleRenderTargets boolean let/var ( textures.length > 1 )
mipmaps any let/var renderTarget.texture.mipmaps
webglTexture any let/var properties.get( textures[ i ] ).__webglTexture
webglTexture any let/var properties.get( textures[ i ] ).__webglTexture
depthStyle any let/var renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT
frame any let/var info.render.frame
colorSpace any let/var texture.colorSpace
format any let/var texture.format
type any let/var texture.type
extension any let/var *not shown*
_occlusion_vertex "\nvoid main() {\n\n\tgl_Position = v... let/var void main() { gl_Position = vec4( position, 1.0 ); }
_occlusion_fragment "\nuniform sampler2DArray depthColor;... let/var ` uniform sampler2DArray depthColor; uniform float depthWidth; uniform float ...
texture ExternalTexture let/var new ExternalTexture( depthData.texture )
viewport any let/var cameraXR.cameras[ 0 ].viewport
material ShaderMaterial let/var new ShaderMaterial( { vertexShader: _occlusion_vertex, fragmentShader: _occlu...
scope this let/var this
session any let/var null
framebufferScaleFactor number let/var 1.0
referenceSpace any let/var null
referenceSpaceType string let/var 'local-floor'
foveation number let/var 1.0
customReferenceSpace any let/var null
pose any let/var null
glBinding any let/var null
glProjLayer any let/var null
glBaseLayer any let/var null
xrFrame any let/var null
depthSensing WebXRDepthSensing let/var new WebXRDepthSensing()
cameraAccessTextures {} let/var {}
initialRenderTarget any let/var null
newRenderTarget any let/var null
controllers any[] let/var []
controllerInputSources any[] let/var []
currentSize Vector2 let/var new Vector2()
currentPixelRatio any let/var null
cameraL PerspectiveCamera let/var new PerspectiveCamera()
cameraR PerspectiveCamera let/var new PerspectiveCamera()
cameras PerspectiveCamera[] let/var [ cameraL, cameraR ]
cameraXR ArrayCamera let/var new ArrayCamera()
_currentDepthNear any let/var null
_currentDepthFar any let/var null
controller any let/var controllers[ index ]
controller any let/var controllers[ index ]
controller any let/var controllers[ index ]
controller any let/var controllers[ controllerIndex ]
inputSource any let/var controllerInputSources[ i ]
useLayers boolean let/var glBinding !== null && 'createProjectionLayer' in XRWebGLBinding.prototype
layerInit { antialias: boolean; alpha: boolean;... let/var { antialias: attributes.antialias, alpha: true, depth: attributes.depth, sten...
depthFormat any let/var null
depthType any let/var null
glDepthFormat any let/var null
projectionlayerInit { colorFormat: 32856; depthFormat: 35... let/var { colorFormat: gl.RGBA8, depthFormat: glDepthFormat, scaleFactor: framebuffer...
inputSource any let/var event.removed[ i ]
inputSource any let/var event.added[ i ]
controller any let/var controllers[ controllerIndex ]
cameraLPos Vector3 let/var new Vector3()
cameraRPos Vector3 let/var new Vector3()
projL number[] let/var cameraL.projectionMatrix.elements
projR number[] let/var cameraR.projectionMatrix.elements
near number let/var projL[ 14 ] / ( projL[ 10 ] - 1 )
far number let/var projL[ 14 ] / ( projL[ 10 ] + 1 )
topFov number let/var ( projL[ 9 ] + 1 ) / projL[ 5 ]
bottomFov number let/var ( projL[ 9 ] - 1 ) / projL[ 5 ]
leftFov number let/var ( projL[ 8 ] - 1 ) / projL[ 0 ]
rightFov number let/var ( projR[ 8 ] + 1 ) / projR[ 0 ]
left number let/var near * leftFov
right number let/var near * rightFov
zOffset number let/var ipd / ( - leftFov + rightFov )
xOffset number let/var zOffset * - leftFov
near2 number let/var near + zOffset
far2 number let/var far + zOffset
left2 number let/var left - xOffset
right2 number let/var right + ( ipd - xOffset )
top2 number let/var topFov * far / far2 * near2
bottom2 number let/var bottomFov * far / far2 * near2
depthNear any let/var camera.near
depthFar any let/var camera.far
parent any let/var camera.parent
cameras PerspectiveCamera[] let/var cameraXR.cameras
onAnimationFrameCallback any let/var null
views any let/var pose.views
cameraXRNeedsUpdate boolean let/var false
view any let/var views[ i ]
viewport any let/var null
camera PerspectiveCamera let/var cameras[ i ]
enabledFeatures any let/var session.enabledFeatures
gpuDepthSensingEnabled boolean let/var enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) && session.dep...
cameraAccessEnabled any let/var enabledFeatures && enabledFeatures.includes( 'camera-access' )
camera any let/var views[ i ].camera
cameraTex any let/var cameraAccessTextures[ camera ]
inputSource any let/var controllerInputSources[ i ]
controller any let/var controllers[ i ]
animation any let/var new WebGLAnimation()
_e1 Euler let/var new Euler()
_m1 Matrix4 let/var new Matrix4()
envMap any let/var materialProperties.envMap
envMapRotation any let/var materialProperties.envMapRotation
light any let/var properties.get( material ).light
buffers {} let/var {}
updateList {} let/var {}
allocatedBindingPoints any[] let/var []
webglProgram any let/var program.program
buffer any let/var buffers[ uniformsGroup.id ]
webglProgram any let/var program.program
frame any let/var info.render.frame
size any let/var uniformsGroup.__size
usage any let/var uniformsGroup.usage
buffer any let/var buffers[ uniformsGroup.id ]
uniforms any let/var uniformsGroup.uniforms
cache any let/var uniformsGroup.__cache
uniformArray any let/var Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]
uniform any let/var uniformArray[ j ]
offset any let/var uniform.__offset
values any let/var Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]
arrayOffset number let/var 0
value any let/var values[ k ]
value any let/var uniform.value
indexString string let/var index + '_' + indexArray
cachedObject any let/var cache[ indexString ]
uniforms any let/var uniformsGroup.uniforms
offset number let/var 0
chunkSize 16 let/var 16
uniformArray any let/var Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ]
uniform any let/var uniformArray[ j ]
values any let/var Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ]
value any let/var values[ k ]
chunkOffset number let/var offset % chunkSize
chunkPadding number let/var chunkOffset % info.boundary
chunkStart number let/var chunkOffset + chunkPadding
chunkOffset number let/var offset % chunkSize
info { boundary: number; storage: number; } let/var { boundary: 0, // bytes storage: 0 // bytes }
uniformsGroup any let/var event.target
_alpha any let/var *not shown*
uintClearColor Uint32Array<ArrayBuffer> let/var new Uint32Array( 4 )
intClearColor Int32Array<ArrayBuffer> let/var new Int32Array( 4 )
currentRenderList any let/var null
currentRenderState any let/var null
renderListStack any[] let/var []
renderStateStack any[] let/var []
_this this let/var this
_isContextLost boolean let/var false
_currentActiveCubeFace number let/var 0
_currentActiveMipmapLevel number let/var 0
_currentRenderTarget any let/var null
_currentMaterialId number let/var -1
_currentCamera any let/var null
_currentViewport Vector4 let/var new Vector4()
_currentScissor Vector4 let/var new Vector4()
_currentScissorTest any let/var null
_currentClearColor Color let/var new Color( 0x000000 )
_currentClearAlpha number let/var 0
_width any let/var canvas.width
_height any let/var canvas.height
_pixelRatio number let/var 1
_opaqueSort any let/var null
_transparentSort any let/var null
_viewport Vector4 let/var new Vector4( 0, 0, _width, _height )
_scissor Vector4 let/var new Vector4( 0, 0, _width, _height )
_scissorTest boolean let/var false
_frustum Frustum let/var new Frustum()
_clippingEnabled boolean let/var false
_localClippingEnabled boolean let/var false
_projScreenMatrix Matrix4 let/var new Matrix4()
_vector3 Vector3 let/var new Vector3()
_vector4 Vector4 let/var new Vector4()
_emptyScene { background: any; fog: any; environm... let/var { background: null, fog: null, environment: null, overrideMaterial: null, isS...
_renderBackground boolean let/var false
_gl any let/var context
contextAttributes { alpha: boolean; depth: any; stencil... let/var { alpha: true, depth, stencil, antialias, premultipliedAlpha, preserveDrawing...
contextName "webgl2" let/var 'webgl2'
extensions any let/var *not shown*
capabilities any let/var *not shown*
state any let/var *not shown*
info any let/var *not shown*
properties any let/var *not shown*
textures any let/var *not shown*
cubemaps any let/var *not shown*
cubeuvmaps any let/var *not shown*
attributes any let/var *not shown*
geometries any let/var *not shown*
objects any let/var *not shown*
programCache any let/var *not shown*
materials any let/var *not shown*
renderLists any let/var *not shown*
renderStates any let/var *not shown*
clipping any let/var *not shown*
shadowMap any let/var *not shown*
background any let/var *not shown*
morphtargets any let/var *not shown*
bufferRenderer any let/var *not shown*
indexedBufferRenderer any let/var *not shown*
utils any let/var *not shown*
bindingStates any let/var *not shown*
uniformsGroups any let/var *not shown*
xr WebXRManager let/var new WebXRManager( _this, _gl )
bits number let/var 0
isIntegerFormat boolean let/var false
targetFormat any let/var _currentRenderTarget.texture.format
targetType any let/var _currentRenderTarget.texture.type
isUnsignedType boolean let/var targetType === UnsignedByteType \|\| targetType === UnsignedIntType \|\| targ...
r any let/var clearColor.r
g any let/var clearColor.g
b any let/var clearColor.b
infoAutoReset any let/var info.autoReset
shadowMapEnabled any let/var shadowMap.enabled
shadowMapAutoUpdate any let/var shadowMap.autoUpdate
shadowMapNeedsUpdate any let/var shadowMap.needsUpdate
shadowMapType any let/var shadowMap.type
material any let/var event.target
programs any let/var properties.get( material ).programs
frontFaceCW boolean let/var ( object.isMesh && object.matrixWorld.determinant() < 0 )
index any let/var geometry.index
rangeFactor number let/var 1
drawRange any let/var geometry.drawRange
position any let/var geometry.attributes.position
drawStart number let/var drawRange.start * rangeFactor
drawEnd number let/var ( drawRange.start + drawRange.count ) * rangeFactor
drawCount number let/var drawEnd - drawStart
attribute any let/var *not shown*
renderer any let/var bufferRenderer
lineWidth any let/var material.linewidth
starts any let/var object._multiDrawStarts
counts any let/var object._multiDrawCounts
drawCount any let/var object._multiDrawCount
bytesPerElement any let/var index ? attributes.get( index ).bytesPerElement : 1
maxInstanceCount any let/var geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity
materials Set<any> let/var new Set()
material any let/var object.material
material2 any let/var material[ i ]
program any let/var materialProperties.currentProgram
onAnimationFrameCallback any let/var null
animation any let/var new WebGLAnimation()
shadowsArray any let/var currentRenderState.state.shadowsArray
opaqueObjects any let/var currentRenderList.opaque
transmissiveObjects any let/var currentRenderList.transmissive
cameras any let/var camera.cameras
camera2 any let/var cameras[ i ]
camera2 any let/var cameras[ i ]
material any let/var object.material
material any let/var object.material
groups any let/var geometry.groups
group any let/var groups[ i ]
groupMaterial any let/var material[ group.materialIndex ]
children any let/var object.children
opaqueObjects any let/var currentRenderList.opaque
transmissiveObjects any let/var currentRenderList.transmissive
transparentObjects any let/var currentRenderList.transparent
overrideMaterial any let/var scene.isScene === true ? scene.overrideMaterial : null
transmissionRenderTarget any let/var currentRenderState.state.transmissionRenderTarget[ camera.id ]
activeViewport any let/var camera.viewport \|\| _currentViewport
currentToneMapping number let/var _this.toneMapping
currentCameraViewport any let/var camera.viewport
renderTargetNeedsUpdate boolean let/var false
renderItem any let/var transmissiveObjects[ i ]
object any let/var renderItem.object
geometry any let/var renderItem.geometry
material any let/var renderItem.material
group any let/var renderItem.group
currentSide any let/var material.side
overrideMaterial any let/var scene.isScene === true ? scene.overrideMaterial : null
renderItem any let/var renderList[ i ]
object any let/var renderItem.object
geometry any let/var renderItem.geometry
group any let/var renderItem.group
material any let/var renderItem.material
lights any let/var currentRenderState.state.lights
shadowsArray any let/var currentRenderState.state.shadowsArray
lightsStateVersion any let/var lights.state.version
programs any let/var materialProperties.programs
uniforms any let/var materialProperties.uniforms
fog any let/var scene.fog
environment any let/var material.isMeshStandardMaterial ? scene.environment : null
colorSpace any let/var ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRender...
vertexAlphas boolean let/var material.vertexColors === true && !! geometry.attributes.color && geometry.at...
vertexTangents boolean let/var !! geometry.attributes.tangent && ( !! material.normalMap \|\| material.aniso...
morphTargets boolean let/var !! geometry.morphAttributes.position
morphNormals boolean let/var !! geometry.morphAttributes.normal
morphColors boolean let/var !! geometry.morphAttributes.color
toneMapping number let/var NoToneMapping
morphAttribute any let/var geometry.morphAttributes.position \|\| geometry.morphAttributes.normal \|\| g...
morphTargetsCount any let/var ( morphAttribute !== undefined ) ? morphAttribute.length : 0
lights any let/var currentRenderState.state.lights
useCache boolean let/var camera === _currentCamera && material.id === _currentMaterialId
needsProgramChange boolean let/var false
program any let/var materialProperties.currentProgram
refreshProgram boolean let/var false
refreshMaterial boolean let/var false
refreshLights boolean let/var false
m_uniforms any let/var materialProperties.uniforms
uCamPos any let/var p_uniforms.map.cameraPosition
skeleton any let/var object.skeleton
morphAttributes any let/var geometry.morphAttributes
groups any let/var material.uniformsGroups
group any let/var groups[ i ]
useDefaultFramebuffer boolean let/var true
framebuffer any let/var null
isCube boolean let/var false
isRenderTarget3D boolean let/var false
depthTexture DepthTexture let/var renderTarget.depthTexture
texture Texture let/var renderTarget.texture
__webglFramebuffer any let/var properties.get( renderTarget ).__webglFramebuffer
layer number let/var activeCubeFace
framebuffer any let/var properties.get( renderTarget ).__webglFramebuffer
texture Texture let/var renderTarget.textures[ textureIndex ]
textureFormat number let/var texture.format
textureType number let/var texture.type
framebuffer any let/var ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__...
framebuffer any let/var properties.get( renderTarget ).__webglFramebuffer
texture Texture let/var renderTarget.textures[ textureIndex ]
textureFormat number let/var texture.format
textureType number let/var texture.type
currFramebuffer any let/var _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webg...
x number let/var position !== null ? position.x : 0
y number let/var position !== null ? position.y : 0
width any let/var *not shown*
height any let/var *not shown*
depth any let/var *not shown*
minX any let/var *not shown*
minY any let/var *not shown*
minZ any let/var *not shown*
dstX any let/var *not shown*
dstY any let/var *not shown*
dstZ any let/var *not shown*
image any let/var srcTexture.isCompressedTexture ? srcTexture.mipmaps[ dstLevel ] : srcTexture....
glTarget any let/var *not shown*
isSrc3D any let/var srcTexture.isDataArrayTexture \|\| srcTexture.isData3DTexture
isDst3D any let/var dstTexture.isDataArrayTexture \|\| dstTexture.isData3DTexture

Re-exports

Type Source Exported Names
named ./three.core.js AdditiveAnimationBlendMode, AlwaysStencilFunc, AmbientLight, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeCamera, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CylinderGeometry, Cylindrical, DataTexture, DataTextureLoader, DataUtils, DecrementStencilOp, DecrementWrapStencilOp, DefaultLoadingManager, DetachedBindMode, DirectionalLight, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicDrawUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, EqualStencilFunc, ExtrudeGeometry, FileLoader, Float16BufferAttribute, Float32BufferAttribute, Fog, FogExp2, FramebufferTexture, FrustumArray, GLBufferAttribute, GLSL1, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, HemisphereLight, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, IncrementStencilOp, IncrementWrapStencilOp, InstancedBufferAttribute, InstancedBufferGeometry, InstancedInterleavedBuffer, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, InterleavedBuffer, InterleavedBufferAttribute, Interpolant, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, InvertStencilOp, KeepStencilOp, KeyframeTrack, LOD, LatheGeometry, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, Material, MaterialLoader, MathUtils, Matrix2, MeshLambertMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NeverStencilFunc, NormalAnimationBlendMode, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, OctahedronGeometry, Path, PlaneHelper, PointLight, PointLightHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, Quaternion, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBDepthPacking, RGBIntegerFormat, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RectAreaLight, RenderTarget, RenderTarget3D, ReplaceStencilOp, RingGeometry, Scene, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphereGeometry, Spherical, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, Timer, TimestampQuery, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, ZeroStencilOp

Functions

WebGLAnimation(): { start: () => void; stop: () => void; setAnimationLoop: (callback: any) => void; setContext: (value: any) => void; }

Returns: { start: () => void; stop: () => void; setAnimationLoop: (callback: any) => void; setContext: (value: any) => void; }

Calls:

  • animationLoop
  • context.requestAnimationFrame
  • context.cancelAnimationFrame
Code
function WebGLAnimation() {

    let context = null;
    let isAnimating = false;
    let animationLoop = null;
    let requestId = null;

    function onAnimationFrame( time, frame ) {

        animationLoop( time, frame );

        requestId = context.requestAnimationFrame( onAnimationFrame );

    }

    return {

        start: function () {

            if ( isAnimating === true ) return;
            if ( animationLoop === null ) return;

            requestId = context.requestAnimationFrame( onAnimationFrame );

            isAnimating = true;

        },

        stop: function () {

            context.cancelAnimationFrame( requestId );

            isAnimating = false;

        },

        setAnimationLoop: function ( callback ) {

            animationLoop = callback;

        },

        setContext: function ( value ) {

            context = value;

        }

    };

}

onAnimationFrame(time: any, frame: any): void

Parameters:

  • time any
  • frame any

Returns: void

Calls:

  • animationLoop
  • context.requestAnimationFrame
Code
function onAnimationFrame( time, frame ) {

        animationLoop( time, frame );

        requestId = context.requestAnimationFrame( onAnimationFrame );

    }

start(): void

Returns: void

Calls:

  • context.requestAnimationFrame
Code
function () {

            if ( isAnimating === true ) return;
            if ( animationLoop === null ) return;

            requestId = context.requestAnimationFrame( onAnimationFrame );

            isAnimating = true;

        }

stop(): void

Returns: void

Calls:

  • context.cancelAnimationFrame
Code
function () {

            context.cancelAnimationFrame( requestId );

            isAnimating = false;

        }

setAnimationLoop(callback: any): void

Parameters:

  • callback any

Returns: void

Code
function ( callback ) {

            animationLoop = callback;

        }

setContext(value: any): void

Parameters:

  • value any

Returns: void

Code
function ( value ) {

            context = value;

        }

start(): void

Returns: void

Calls:

  • context.requestAnimationFrame
Code
function () {

            if ( isAnimating === true ) return;
            if ( animationLoop === null ) return;

            requestId = context.requestAnimationFrame( onAnimationFrame );

            isAnimating = true;

        }

stop(): void

Returns: void

Calls:

  • context.cancelAnimationFrame
Code
function () {

            context.cancelAnimationFrame( requestId );

            isAnimating = false;

        }

setAnimationLoop(callback: any): void

Parameters:

  • callback any

Returns: void

Code
function ( callback ) {

            animationLoop = callback;

        }

setContext(value: any): void

Parameters:

  • value any

Returns: void

Code
function ( value ) {

            context = value;

        }

WebGLAttributes(gl: any): { get: (attribute: any) => any; remove: (attribute: any) => void; update: (attribute: any, bufferType: any) => void; }

Parameters:

  • gl any

Returns: { get: (attribute: any) => any; remove: (attribute: any) => void; update: (attribute: any, bufferType: any) => void; }

Calls:

  • gl.createBuffer
  • gl.bindBuffer
  • gl.bufferData
  • attribute.onUploadCallback
  • gl.bufferSubData
  • updateRanges.sort
  • Math.max
  • attribute.clearUpdateRanges
  • buffers.get
  • gl.deleteBuffer
  • buffers.delete
  • buffers.set
  • createBuffer
  • updateBuffer

Internal Comments:

// Not using update ranges (x4)
// Before applying update ranges, we merge any adjacent / overlapping (x4)
// ranges to reduce load on `gl.bufferSubData`. Empirically, this has led (x4)
// to performance improvements for applications which make heavy use of (x4)
// update ranges. Likely due to GPU command overhead. (x4)
// (x5)
// Note that to reduce garbage collection between frames, we merge the (x4)
// update ranges in-place. This is safe because this method will clear the (x4)
// update ranges once updated. (x4)
// To merge the update ranges in-place, we work from left to right in the (x2)
// existing updateRanges array, merging ranges. This may result in a final (x2)
// array which is smaller than the original. This index tracks the last (x2)
// index representing a merged range, any data after this index can be (x2)
// trimmed once the merge algorithm is completed. (x2)
// We add one here to merge adjacent ranges. This is safe because ranges
// operate over positive integers.
// Trim the array to only contain the merged ranges. (x4)

Code
function WebGLAttributes( gl ) {

    const buffers = new WeakMap();

    function createBuffer( attribute, bufferType ) {

        const array = attribute.array;
        const usage = attribute.usage;
        const size = array.byteLength;

        const buffer = gl.createBuffer();

        gl.bindBuffer( bufferType, buffer );
        gl.bufferData( bufferType, array, usage );

        attribute.onUploadCallback();

        let type;

        if ( array instanceof Float32Array ) {

            type = gl.FLOAT;

        } else if ( typeof Float16Array !== 'undefined' && array instanceof Float16Array ) {

            type = gl.HALF_FLOAT;

        } else if ( array instanceof Uint16Array ) {

            if ( attribute.isFloat16BufferAttribute ) {

                type = gl.HALF_FLOAT;

            } else {

                type = gl.UNSIGNED_SHORT;

            }

        } else if ( array instanceof Int16Array ) {

            type = gl.SHORT;

        } else if ( array instanceof Uint32Array ) {

            type = gl.UNSIGNED_INT;

        } else if ( array instanceof Int32Array ) {

            type = gl.INT;

        } else if ( array instanceof Int8Array ) {

            type = gl.BYTE;

        } else if ( array instanceof Uint8Array ) {

            type = gl.UNSIGNED_BYTE;

        } else if ( array instanceof Uint8ClampedArray ) {

            type = gl.UNSIGNED_BYTE;

        } else {

            throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );

        }

        return {
            buffer: buffer,
            type: type,
            bytesPerElement: array.BYTES_PER_ELEMENT,
            version: attribute.version,
            size: size
        };

    }

    function updateBuffer( buffer, attribute, bufferType ) {

        const array = attribute.array;
        const updateRanges = attribute.updateRanges;

        gl.bindBuffer( bufferType, buffer );

        if ( updateRanges.length === 0 ) {

            // Not using update ranges
            gl.bufferSubData( bufferType, 0, array );

        } else {

            // Before applying update ranges, we merge any adjacent / overlapping
            // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led
            // to performance improvements for applications which make heavy use of
            // update ranges. Likely due to GPU command overhead.
            //
            // Note that to reduce garbage collection between frames, we merge the
            // update ranges in-place. This is safe because this method will clear the
            // update ranges once updated.

            updateRanges.sort( ( a, b ) => a.start - b.start );

            // To merge the update ranges in-place, we work from left to right in the
            // existing updateRanges array, merging ranges. This may result in a final
            // array which is smaller than the original. This index tracks the last
            // index representing a merged range, any data after this index can be
            // trimmed once the merge algorithm is completed.
            let mergeIndex = 0;

            for ( let i = 1; i < updateRanges.length; i ++ ) {

                const previousRange = updateRanges[ mergeIndex ];
                const range = updateRanges[ i ];

                // We add one here to merge adjacent ranges. This is safe because ranges
                // operate over positive integers.
                if ( range.start <= previousRange.start + previousRange.count + 1 ) {

                    previousRange.count = Math.max(
                        previousRange.count,
                        range.start + range.count - previousRange.start
                    );

                } else {

                    ++ mergeIndex;
                    updateRanges[ mergeIndex ] = range;

                }

            }

            // Trim the array to only contain the merged ranges.
            updateRanges.length = mergeIndex + 1;

            for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {

                const range = updateRanges[ i ];

                gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
                    array, range.start, range.count );

            }

            attribute.clearUpdateRanges();

        }

        attribute.onUploadCallback();

    }

    //

    function get( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        return buffers.get( attribute );

    }

    function remove( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        const data = buffers.get( attribute );

        if ( data ) {

            gl.deleteBuffer( data.buffer );

            buffers.delete( attribute );

        }

    }

    function update( attribute, bufferType ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        if ( attribute.isGLBufferAttribute ) {

            const cached = buffers.get( attribute );

            if ( ! cached || cached.version < attribute.version ) {

                buffers.set( attribute, {
                    buffer: attribute.buffer,
                    type: attribute.type,
                    bytesPerElement: attribute.elementSize,
                    version: attribute.version
                } );

            }

            return;

        }

        const data = buffers.get( attribute );

        if ( data === undefined ) {

            buffers.set( attribute, createBuffer( attribute, bufferType ) );

        } 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;

        }

    }

    return {

        get: get,
        remove: remove,
        update: update

    };

}

createBuffer(attribute: any, bufferType: any): { buffer: any; type: any; bytesPerElement: number; version: any; size: any; }

Parameters:

  • attribute any
  • bufferType any

Returns: { buffer: any; type: any; bytesPerElement: number; version: any; size: any; }

Calls:

  • gl.createBuffer
  • gl.bindBuffer
  • gl.bufferData
  • attribute.onUploadCallback
Code
function createBuffer( attribute, bufferType ) {

        const array = attribute.array;
        const usage = attribute.usage;
        const size = array.byteLength;

        const buffer = gl.createBuffer();

        gl.bindBuffer( bufferType, buffer );
        gl.bufferData( bufferType, array, usage );

        attribute.onUploadCallback();

        let type;

        if ( array instanceof Float32Array ) {

            type = gl.FLOAT;

        } else if ( typeof Float16Array !== 'undefined' && array instanceof Float16Array ) {

            type = gl.HALF_FLOAT;

        } else if ( array instanceof Uint16Array ) {

            if ( attribute.isFloat16BufferAttribute ) {

                type = gl.HALF_FLOAT;

            } else {

                type = gl.UNSIGNED_SHORT;

            }

        } else if ( array instanceof Int16Array ) {

            type = gl.SHORT;

        } else if ( array instanceof Uint32Array ) {

            type = gl.UNSIGNED_INT;

        } else if ( array instanceof Int32Array ) {

            type = gl.INT;

        } else if ( array instanceof Int8Array ) {

            type = gl.BYTE;

        } else if ( array instanceof Uint8Array ) {

            type = gl.UNSIGNED_BYTE;

        } else if ( array instanceof Uint8ClampedArray ) {

            type = gl.UNSIGNED_BYTE;

        } else {

            throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );

        }

        return {
            buffer: buffer,
            type: type,
            bytesPerElement: array.BYTES_PER_ELEMENT,
            version: attribute.version,
            size: size
        };

    }

updateBuffer(buffer: any, attribute: any, bufferType: any): void

Parameters:

  • buffer any
  • attribute any
  • bufferType any

Returns: void

Calls:

  • gl.bindBuffer
  • gl.bufferSubData
  • updateRanges.sort
  • Math.max
  • attribute.clearUpdateRanges
  • attribute.onUploadCallback

Internal Comments:

// Not using update ranges (x4)
// Before applying update ranges, we merge any adjacent / overlapping (x4)
// ranges to reduce load on `gl.bufferSubData`. Empirically, this has led (x4)
// to performance improvements for applications which make heavy use of (x4)
// update ranges. Likely due to GPU command overhead. (x4)
// (x4)
// Note that to reduce garbage collection between frames, we merge the (x4)
// update ranges in-place. This is safe because this method will clear the (x4)
// update ranges once updated. (x4)
// To merge the update ranges in-place, we work from left to right in the (x2)
// existing updateRanges array, merging ranges. This may result in a final (x2)
// array which is smaller than the original. This index tracks the last (x2)
// index representing a merged range, any data after this index can be (x2)
// trimmed once the merge algorithm is completed. (x2)
// We add one here to merge adjacent ranges. This is safe because ranges
// operate over positive integers.
// Trim the array to only contain the merged ranges. (x4)

Code
function updateBuffer( buffer, attribute, bufferType ) {

        const array = attribute.array;
        const updateRanges = attribute.updateRanges;

        gl.bindBuffer( bufferType, buffer );

        if ( updateRanges.length === 0 ) {

            // Not using update ranges
            gl.bufferSubData( bufferType, 0, array );

        } else {

            // Before applying update ranges, we merge any adjacent / overlapping
            // ranges to reduce load on `gl.bufferSubData`. Empirically, this has led
            // to performance improvements for applications which make heavy use of
            // update ranges. Likely due to GPU command overhead.
            //
            // Note that to reduce garbage collection between frames, we merge the
            // update ranges in-place. This is safe because this method will clear the
            // update ranges once updated.

            updateRanges.sort( ( a, b ) => a.start - b.start );

            // To merge the update ranges in-place, we work from left to right in the
            // existing updateRanges array, merging ranges. This may result in a final
            // array which is smaller than the original. This index tracks the last
            // index representing a merged range, any data after this index can be
            // trimmed once the merge algorithm is completed.
            let mergeIndex = 0;

            for ( let i = 1; i < updateRanges.length; i ++ ) {

                const previousRange = updateRanges[ mergeIndex ];
                const range = updateRanges[ i ];

                // We add one here to merge adjacent ranges. This is safe because ranges
                // operate over positive integers.
                if ( range.start <= previousRange.start + previousRange.count + 1 ) {

                    previousRange.count = Math.max(
                        previousRange.count,
                        range.start + range.count - previousRange.start
                    );

                } else {

                    ++ mergeIndex;
                    updateRanges[ mergeIndex ] = range;

                }

            }

            // Trim the array to only contain the merged ranges.
            updateRanges.length = mergeIndex + 1;

            for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {

                const range = updateRanges[ i ];

                gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
                    array, range.start, range.count );

            }

            attribute.clearUpdateRanges();

        }

        attribute.onUploadCallback();

    }

get(attribute: any): any

Parameters:

  • attribute any

Returns: any

Calls:

  • buffers.get
Code
function get( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        return buffers.get( attribute );

    }

remove(attribute: any): void

Parameters:

  • attribute any

Returns: void

Calls:

  • buffers.get
  • gl.deleteBuffer
  • buffers.delete
Code
function remove( attribute ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        const data = buffers.get( attribute );

        if ( data ) {

            gl.deleteBuffer( data.buffer );

            buffers.delete( attribute );

        }

    }

update(attribute: any, bufferType: any): void

Parameters:

  • attribute any
  • bufferType any

Returns: void

Calls:

  • buffers.get
  • buffers.set
  • createBuffer
  • updateBuffer
Code
function update( attribute, bufferType ) {

        if ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;

        if ( attribute.isGLBufferAttribute ) {

            const cached = buffers.get( attribute );

            if ( ! cached || cached.version < attribute.version ) {

                buffers.set( attribute, {
                    buffer: attribute.buffer,
                    type: attribute.type,
                    bytesPerElement: attribute.elementSize,
                    version: attribute.version
                } );

            }

            return;

        }

        const data = buffers.get( attribute );

        if ( data === undefined ) {

            buffers.set( attribute, createBuffer( attribute, bufferType ) );

        } 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;

        }

    }

WebGLBackground(renderer: any, cubemaps: any, cubeuvmaps: any, state: any, objects: any, alpha: any, premultipliedAlpha: any): { getClearColor: () => Color; setClearColor: (color: any, alpha?: number) => void; getClearAlpha: () => number; setClearAlpha: (alpha: any) => void; render: (scene: any) => void; addToRenderList: (renderList: any, scene: any) => void; dispose: () => void; }

Parameters:

  • renderer any
  • cubemaps any
  • cubeuvmaps any
  • state any
  • objects any
  • alpha any
  • premultipliedAlpha any

Returns: { getClearColor: () => Color; setClearColor: (color: any, alpha?: number) => void; getClearAlpha: () => number; setClearAlpha: (alpha: any) => void; render: (scene: any) => void; addToRenderList: (renderList: any, scene: any) => void; dispose: () => void; }

Calls:

  • ( usePMREM ? cubeuvmaps : cubemaps ).get
  • getBackground
  • setClear
  • renderer.xr.getEnvironmentBlendMode
  • state.buffers.color.setClear
  • state.buffers.depth.setTest
  • state.buffers.depth.setMask
  • state.buffers.color.setMask
  • renderer.clear
  • cloneUniforms (from ./three.core.js)
  • boxMesh.geometry.deleteAttribute
  • this.matrixWorld.copyPosition
  • Object.defineProperty
  • objects.update
  • _e1$1.copy
  • boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4
  • _m1$1.makeRotationFromEuler
  • ColorManagement.getTransfer
  • boxMesh.layers.enableAll
  • renderList.unshift
  • planeMesh.geometry.deleteAttribute
  • background.updateMatrix
  • planeMesh.material.uniforms.uvTransform.value.copy
  • planeMesh.layers.enableAll
  • color.getRGB
  • getUnlitUniformColorSpace (from ./three.core.js)
  • boxMesh.geometry.dispose
  • boxMesh.material.dispose
  • planeMesh.geometry.dispose
  • planeMesh.material.dispose
  • clearColor.set

Internal Comments:

// buffers might not be writable which is required to ensure a correct clear (x6)
// add "envMap" material property so the renderer can evaluate it like for built-in materials (x4)
// accommodate left-handed frame (x4)
// environment maps which are not cube render targets or PMREMs follow a different convention (x4)
// push to the pre-sorted opaque render list (x8)
// add "map" material property so the renderer can evaluate it like for built-in materials (x4)

Code
function WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) {

    const clearColor = new Color( 0x000000 );
    let clearAlpha = alpha === true ? 0 : 1;

    let planeMesh;
    let boxMesh;

    let currentBackground = null;
    let currentBackgroundVersion = 0;
    let currentTonemapping = null;

    function getBackground( scene ) {

        let background = scene.isScene === true ? scene.background : null;

        if ( background && background.isTexture ) {

            const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background
            background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );

        }

        return background;

    }

    function render( scene ) {

        let forceClear = false;
        const background = getBackground( scene );

        if ( background === null ) {

            setClear( clearColor, clearAlpha );

        } else if ( background && background.isColor ) {

            setClear( background, 1 );
            forceClear = true;

        }

        const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();

        if ( environmentBlendMode === 'additive' ) {

            state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );

        } else if ( environmentBlendMode === 'alpha-blend' ) {

            state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );

        }

        if ( renderer.autoClear || forceClear ) {

            // buffers might not be writable which is required to ensure a correct clear

            state.buffers.depth.setTest( true );
            state.buffers.depth.setMask( true );
            state.buffers.color.setMask( true );

            renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );

        }

    }

    function addToRenderList( renderList, scene ) {

        const background = getBackground( scene );

        if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {

            if ( boxMesh === undefined ) {

                boxMesh = new Mesh(
                    new BoxGeometry( 1, 1, 1 ),
                    new ShaderMaterial( {
                        name: 'BackgroundCubeMaterial',
                        uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
                        vertexShader: ShaderLib.backgroundCube.vertexShader,
                        fragmentShader: ShaderLib.backgroundCube.fragmentShader,
                        side: BackSide,
                        depthTest: false,
                        depthWrite: false,
                        fog: false,
                        allowOverride: false
                    } )
                );

                boxMesh.geometry.deleteAttribute( 'normal' );
                boxMesh.geometry.deleteAttribute( 'uv' );

                boxMesh.onBeforeRender = function ( renderer, scene, camera ) {

                    this.matrixWorld.copyPosition( camera.matrixWorld );

                };

                // add "envMap" material property so the renderer can evaluate it like for built-in materials
                Object.defineProperty( boxMesh.material, 'envMap', {

                    get: function () {

                        return this.uniforms.envMap.value;

                    }

                } );

                objects.update( boxMesh );

            }

            _e1$1.copy( scene.backgroundRotation );

            // accommodate left-handed frame
            _e1$1.x *= -1; _e1$1.y *= -1; _e1$1.z *= -1;

            if ( background.isCubeTexture && background.isRenderTargetTexture === false ) {

                // environment maps which are not cube render targets or PMREMs follow a different convention
                _e1$1.y *= -1;
                _e1$1.z *= -1;

            }

            boxMesh.material.uniforms.envMap.value = background;
            boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? -1 : 1;
            boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
            boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
            boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( _e1$1 ) );
            boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;

            if ( currentBackground !== background ||
                currentBackgroundVersion !== background.version ||
                currentTonemapping !== renderer.toneMapping ) {

                boxMesh.material.needsUpdate = true;

                currentBackground = background;
                currentBackgroundVersion = background.version;
                currentTonemapping = renderer.toneMapping;

            }

            boxMesh.layers.enableAll();

            // push to the pre-sorted opaque render list
            renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );

        } else if ( background && background.isTexture ) {

            if ( planeMesh === undefined ) {

                planeMesh = new Mesh(
                    new PlaneGeometry( 2, 2 ),
                    new ShaderMaterial( {
                        name: 'BackgroundMaterial',
                        uniforms: cloneUniforms( ShaderLib.background.uniforms ),
                        vertexShader: ShaderLib.background.vertexShader,
                        fragmentShader: ShaderLib.background.fragmentShader,
                        side: FrontSide,
                        depthTest: false,
                        depthWrite: false,
                        fog: false,
                        allowOverride: false
                    } )
                );

                planeMesh.geometry.deleteAttribute( 'normal' );

                // add "map" material property so the renderer can evaluate it like for built-in materials
                Object.defineProperty( planeMesh.material, 'map', {

                    get: function () {

                        return this.uniforms.t2D.value;

                    }

                } );

                objects.update( planeMesh );

            }

            planeMesh.material.uniforms.t2D.value = background;
            planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
            planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;

            if ( background.matrixAutoUpdate === true ) {

                background.updateMatrix();

            }

            planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );

            if ( currentBackground !== background ||
                currentBackgroundVersion !== background.version ||
                currentTonemapping !== renderer.toneMapping ) {

                planeMesh.material.needsUpdate = true;

                currentBackground = background;
                currentBackgroundVersion = background.version;
                currentTonemapping = renderer.toneMapping;

            }

            planeMesh.layers.enableAll();

            // push to the pre-sorted opaque render list
            renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );

        }

    }

    function setClear( color, alpha ) {

        color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );

        state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );

    }

    function dispose() {

        if ( boxMesh !== undefined ) {

            boxMesh.geometry.dispose();
            boxMesh.material.dispose();

            boxMesh = undefined;

        }

        if ( planeMesh !== undefined ) {

            planeMesh.geometry.dispose();
            planeMesh.material.dispose();

            planeMesh = undefined;

        }

    }

    return {

        getClearColor: function () {

            return clearColor;

        },
        setClearColor: function ( color, alpha = 1 ) {

            clearColor.set( color );
            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        },
        getClearAlpha: function () {

            return clearAlpha;

        },
        setClearAlpha: function ( alpha ) {

            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        },
        render: render,
        addToRenderList: addToRenderList,
        dispose: dispose

    };

}

getBackground(scene: any): any

Parameters:

  • scene any

Returns: any

Calls:

  • ( usePMREM ? cubeuvmaps : cubemaps ).get
Code
function getBackground( scene ) {

        let background = scene.isScene === true ? scene.background : null;

        if ( background && background.isTexture ) {

            const usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background
            background = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );

        }

        return background;

    }

render(scene: any): void

Parameters:

  • scene any

Returns: void

Calls:

  • getBackground
  • setClear
  • renderer.xr.getEnvironmentBlendMode
  • state.buffers.color.setClear
  • state.buffers.depth.setTest
  • state.buffers.depth.setMask
  • state.buffers.color.setMask
  • renderer.clear

Internal Comments:

// buffers might not be writable which is required to ensure a correct clear (x6)

Code
function render( scene ) {

        let forceClear = false;
        const background = getBackground( scene );

        if ( background === null ) {

            setClear( clearColor, clearAlpha );

        } else if ( background && background.isColor ) {

            setClear( background, 1 );
            forceClear = true;

        }

        const environmentBlendMode = renderer.xr.getEnvironmentBlendMode();

        if ( environmentBlendMode === 'additive' ) {

            state.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );

        } else if ( environmentBlendMode === 'alpha-blend' ) {

            state.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );

        }

        if ( renderer.autoClear || forceClear ) {

            // buffers might not be writable which is required to ensure a correct clear

            state.buffers.depth.setTest( true );
            state.buffers.depth.setMask( true );
            state.buffers.color.setMask( true );

            renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );

        }

    }

addToRenderList(renderList: any, scene: any): void

Parameters:

  • renderList any
  • scene any

Returns: void

Calls:

  • getBackground
  • cloneUniforms (from ./three.core.js)
  • boxMesh.geometry.deleteAttribute
  • this.matrixWorld.copyPosition
  • Object.defineProperty
  • objects.update
  • _e1$1.copy
  • boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4
  • _m1$1.makeRotationFromEuler
  • ColorManagement.getTransfer
  • boxMesh.layers.enableAll
  • renderList.unshift
  • planeMesh.geometry.deleteAttribute
  • background.updateMatrix
  • planeMesh.material.uniforms.uvTransform.value.copy
  • planeMesh.layers.enableAll

Internal Comments:

// add "envMap" material property so the renderer can evaluate it like for built-in materials (x4)
// accommodate left-handed frame (x4)
// environment maps which are not cube render targets or PMREMs follow a different convention (x4)
// push to the pre-sorted opaque render list (x8)
// add "map" material property so the renderer can evaluate it like for built-in materials (x4)

Code
function addToRenderList( renderList, scene ) {

        const background = getBackground( scene );

        if ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {

            if ( boxMesh === undefined ) {

                boxMesh = new Mesh(
                    new BoxGeometry( 1, 1, 1 ),
                    new ShaderMaterial( {
                        name: 'BackgroundCubeMaterial',
                        uniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),
                        vertexShader: ShaderLib.backgroundCube.vertexShader,
                        fragmentShader: ShaderLib.backgroundCube.fragmentShader,
                        side: BackSide,
                        depthTest: false,
                        depthWrite: false,
                        fog: false,
                        allowOverride: false
                    } )
                );

                boxMesh.geometry.deleteAttribute( 'normal' );
                boxMesh.geometry.deleteAttribute( 'uv' );

                boxMesh.onBeforeRender = function ( renderer, scene, camera ) {

                    this.matrixWorld.copyPosition( camera.matrixWorld );

                };

                // add "envMap" material property so the renderer can evaluate it like for built-in materials
                Object.defineProperty( boxMesh.material, 'envMap', {

                    get: function () {

                        return this.uniforms.envMap.value;

                    }

                } );

                objects.update( boxMesh );

            }

            _e1$1.copy( scene.backgroundRotation );

            // accommodate left-handed frame
            _e1$1.x *= -1; _e1$1.y *= -1; _e1$1.z *= -1;

            if ( background.isCubeTexture && background.isRenderTargetTexture === false ) {

                // environment maps which are not cube render targets or PMREMs follow a different convention
                _e1$1.y *= -1;
                _e1$1.z *= -1;

            }

            boxMesh.material.uniforms.envMap.value = background;
            boxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? -1 : 1;
            boxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;
            boxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
            boxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( _e1$1 ) );
            boxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;

            if ( currentBackground !== background ||
                currentBackgroundVersion !== background.version ||
                currentTonemapping !== renderer.toneMapping ) {

                boxMesh.material.needsUpdate = true;

                currentBackground = background;
                currentBackgroundVersion = background.version;
                currentTonemapping = renderer.toneMapping;

            }

            boxMesh.layers.enableAll();

            // push to the pre-sorted opaque render list
            renderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );

        } else if ( background && background.isTexture ) {

            if ( planeMesh === undefined ) {

                planeMesh = new Mesh(
                    new PlaneGeometry( 2, 2 ),
                    new ShaderMaterial( {
                        name: 'BackgroundMaterial',
                        uniforms: cloneUniforms( ShaderLib.background.uniforms ),
                        vertexShader: ShaderLib.background.vertexShader,
                        fragmentShader: ShaderLib.background.fragmentShader,
                        side: FrontSide,
                        depthTest: false,
                        depthWrite: false,
                        fog: false,
                        allowOverride: false
                    } )
                );

                planeMesh.geometry.deleteAttribute( 'normal' );

                // add "map" material property so the renderer can evaluate it like for built-in materials
                Object.defineProperty( planeMesh.material, 'map', {

                    get: function () {

                        return this.uniforms.t2D.value;

                    }

                } );

                objects.update( planeMesh );

            }

            planeMesh.material.uniforms.t2D.value = background;
            planeMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;
            planeMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;

            if ( background.matrixAutoUpdate === true ) {

                background.updateMatrix();

            }

            planeMesh.material.uniforms.uvTransform.value.copy( background.matrix );

            if ( currentBackground !== background ||
                currentBackgroundVersion !== background.version ||
                currentTonemapping !== renderer.toneMapping ) {

                planeMesh.material.needsUpdate = true;

                currentBackground = background;
                currentBackgroundVersion = background.version;
                currentTonemapping = renderer.toneMapping;

            }

            planeMesh.layers.enableAll();

            // push to the pre-sorted opaque render list
            renderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );

        }

    }

get(): any

Returns: any

Code
function () {

                        return this.uniforms.envMap.value;

                    }

get(): any

Returns: any

Code
function () {

                        return this.uniforms.envMap.value;

                    }

get(): any

Returns: any

Code
function () {

                        return this.uniforms.t2D.value;

                    }

get(): any

Returns: any

Code
function () {

                        return this.uniforms.t2D.value;

                    }

setClear(color: any, alpha: any): void

Parameters:

  • color any
  • alpha any

Returns: void

Calls:

  • color.getRGB
  • getUnlitUniformColorSpace (from ./three.core.js)
  • state.buffers.color.setClear
Code
function setClear( color, alpha ) {

        color.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );

        state.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );

    }

dispose(): void

Returns: void

Calls:

  • boxMesh.geometry.dispose
  • boxMesh.material.dispose
  • planeMesh.geometry.dispose
  • planeMesh.material.dispose
Code
function dispose() {

        if ( boxMesh !== undefined ) {

            boxMesh.geometry.dispose();
            boxMesh.material.dispose();

            boxMesh = undefined;

        }

        if ( planeMesh !== undefined ) {

            planeMesh.geometry.dispose();
            planeMesh.material.dispose();

            planeMesh = undefined;

        }

    }

getClearColor(): Color

Returns: Color

Code
function () {

            return clearColor;

        }

setClearColor(color: any, alpha: number): void

Parameters:

  • color any
  • alpha number

Returns: void

Calls:

  • clearColor.set
  • setClear
Code
function ( color, alpha = 1 ) {

            clearColor.set( color );
            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        }

getClearAlpha(): number

Returns: number

Code
function () {

            return clearAlpha;

        }

setClearAlpha(alpha: any): void

Parameters:

  • alpha any

Returns: void

Calls:

  • setClear
Code
function ( alpha ) {

            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        }

getClearColor(): Color

Returns: Color

Code
function () {

            return clearColor;

        }

setClearColor(color: any, alpha: number): void

Parameters:

  • color any
  • alpha number

Returns: void

Calls:

  • clearColor.set
  • setClear
Code
function ( color, alpha = 1 ) {

            clearColor.set( color );
            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        }

getClearAlpha(): number

Returns: number

Code
function () {

            return clearAlpha;

        }

setClearAlpha(alpha: any): void

Parameters:

  • alpha any

Returns: void

Calls:

  • setClear
Code
function ( alpha ) {

            clearAlpha = alpha;
            setClear( clearColor, clearAlpha );

        }

WebGLBindingStates(gl: any, attributes: any): { setup: (object: any, material: any, program: any, geometry: any, index: any) => void; reset: () => void; resetDefaultState: () => void; dispose: () => void; releaseStatesOfGeometry: (geometry: any) => void; releaseStatesOfProgram: (program: any) => void; initAttributes: () => void; enableAttribute: (attribute: any...

Parameters:

  • gl any
  • attributes any

Returns: { setup: (object: any, material: any, program: any, geometry: any, index: any) => void; reset: () => void; resetDefaultState: () => void; dispose: () => void; releaseStatesOfGeometry: (geometry: any) => void; releaseStatesOfProgram: (program: any) => void; initAttributes: () => void; enableAttribute: (attribute: any...

Calls:

  • gl.getParameter
  • createBindingState
  • getBindingState
  • bindVertexArrayObject
  • needsUpdate
  • saveCache
  • attributes.update
  • setupVertexAttributes
  • gl.bindBuffer
  • attributes.get
  • gl.createVertexArray
  • gl.bindVertexArray
  • gl.deleteVertexArray
  • createVertexArrayObject
  • program.getAttributes
  • enableAttributeAndDivisor
  • gl.enableVertexAttribArray
  • gl.vertexAttribDivisor
  • gl.disableVertexAttribArray
  • gl.vertexAttribIPointer
  • gl.vertexAttribPointer
  • initAttributes
  • enableAttribute
  • vertexAttribPointer
  • gl.vertexAttrib2fv
  • gl.vertexAttrib3fv
  • gl.vertexAttrib4fv
  • gl.vertexAttrib1fv
  • disableUnusedAttributes
  • reset
  • deleteVertexArrayObject
  • resetDefaultState

Internal Comments:

// for backward compatibility on non-VAO support browser (x2)
// TODO Attribute may not be available on context restore
// check for integer attributes (x2)
// for backward-compatibility

Code
function WebGLBindingStates( gl, attributes ) {

    const maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );

    const bindingStates = {};

    const defaultState = createBindingState( null );
    let currentState = defaultState;
    let forceUpdate = false;

    function setup( object, material, program, geometry, index ) {

        let updateBuffers = false;

        const state = getBindingState( geometry, program, material );

        if ( currentState !== state ) {

            currentState = state;
            bindVertexArrayObject( currentState.object );

        }

        updateBuffers = needsUpdate( object, geometry, program, index );

        if ( updateBuffers ) saveCache( object, geometry, program, index );

        if ( index !== null ) {

            attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );

        }

        if ( updateBuffers || forceUpdate ) {

            forceUpdate = false;

            setupVertexAttributes( object, material, program, geometry );

            if ( index !== null ) {

                gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );

            }

        }

    }

    function createVertexArrayObject() {

        return gl.createVertexArray();

    }

    function bindVertexArrayObject( vao ) {

        return gl.bindVertexArray( vao );

    }

    function deleteVertexArrayObject( vao ) {

        return gl.deleteVertexArray( vao );

    }

    function getBindingState( geometry, program, material ) {

        const wireframe = ( material.wireframe === true );

        let programMap = bindingStates[ geometry.id ];

        if ( programMap === undefined ) {

            programMap = {};
            bindingStates[ geometry.id ] = programMap;

        }

        let stateMap = programMap[ program.id ];

        if ( stateMap === undefined ) {

            stateMap = {};
            programMap[ program.id ] = stateMap;

        }

        let state = stateMap[ wireframe ];

        if ( state === undefined ) {

            state = createBindingState( createVertexArrayObject() );
            stateMap[ wireframe ] = state;

        }

        return state;

    }

    function createBindingState( vao ) {

        const newAttributes = [];
        const enabledAttributes = [];
        const attributeDivisors = [];

        for ( let i = 0; i < maxVertexAttributes; i ++ ) {

            newAttributes[ i ] = 0;
            enabledAttributes[ i ] = 0;
            attributeDivisors[ i ] = 0;

        }

        return {

            // for backward compatibility on non-VAO support browser
            geometry: null,
            program: null,
            wireframe: false,

            newAttributes: newAttributes,
            enabledAttributes: enabledAttributes,
            attributeDivisors: attributeDivisors,
            object: vao,
            attributes: {},
            index: null

        };

    }

    function needsUpdate( object, geometry, program, index ) {

        const cachedAttributes = currentState.attributes;
        const geometryAttributes = geometry.attributes;

        let attributesNum = 0;

        const programAttributes = program.getAttributes();

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                const cachedAttribute = cachedAttributes[ name ];
                let geometryAttribute = geometryAttributes[ name ];

                if ( geometryAttribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;

                }

                if ( cachedAttribute === undefined ) return true;

                if ( cachedAttribute.attribute !== geometryAttribute ) return true;

                if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;

                attributesNum ++;

            }

        }

        if ( currentState.attributesNum !== attributesNum ) return true;

        if ( currentState.index !== index ) return true;

        return false;

    }

    function saveCache( object, geometry, program, index ) {

        const cache = {};
        const attributes = geometry.attributes;
        let attributesNum = 0;

        const programAttributes = program.getAttributes();

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                let attribute = attributes[ name ];

                if ( attribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;

                }

                const data = {};
                data.attribute = attribute;

                if ( attribute && attribute.data ) {

                    data.data = attribute.data;

                }

                cache[ name ] = data;

                attributesNum ++;

            }

        }

        currentState.attributes = cache;
        currentState.attributesNum = attributesNum;

        currentState.index = index;

    }

    function initAttributes() {

        const newAttributes = currentState.newAttributes;

        for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {

            newAttributes[ i ] = 0;

        }

    }

    function enableAttribute( attribute ) {

        enableAttributeAndDivisor( attribute, 0 );

    }

    function enableAttributeAndDivisor( attribute, meshPerAttribute ) {

        const newAttributes = currentState.newAttributes;
        const enabledAttributes = currentState.enabledAttributes;
        const attributeDivisors = currentState.attributeDivisors;

        newAttributes[ attribute ] = 1;

        if ( enabledAttributes[ attribute ] === 0 ) {

            gl.enableVertexAttribArray( attribute );
            enabledAttributes[ attribute ] = 1;

        }

        if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {

            gl.vertexAttribDivisor( attribute, meshPerAttribute );
            attributeDivisors[ attribute ] = meshPerAttribute;

        }

    }

    function disableUnusedAttributes() {

        const newAttributes = currentState.newAttributes;
        const enabledAttributes = currentState.enabledAttributes;

        for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {

            if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {

                gl.disableVertexAttribArray( i );
                enabledAttributes[ i ] = 0;

            }

        }

    }

    function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {

        if ( integer === true ) {

            gl.vertexAttribIPointer( index, size, type, stride, offset );

        } else {

            gl.vertexAttribPointer( index, size, type, normalized, stride, offset );

        }

    }

    function setupVertexAttributes( object, material, program, geometry ) {

        initAttributes();

        const geometryAttributes = geometry.attributes;

        const programAttributes = program.getAttributes();

        const materialDefaultAttributeValues = material.defaultAttributeValues;

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                let geometryAttribute = geometryAttributes[ name ];

                if ( geometryAttribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;

                }

                if ( geometryAttribute !== undefined ) {

                    const normalized = geometryAttribute.normalized;
                    const size = geometryAttribute.itemSize;

                    const attribute = attributes.get( geometryAttribute );

                    // TODO Attribute may not be available on context restore

                    if ( attribute === undefined ) continue;

                    const buffer = attribute.buffer;
                    const type = attribute.type;
                    const bytesPerElement = attribute.bytesPerElement;

                    // check for integer attributes

                    const integer = ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType );

                    if ( geometryAttribute.isInterleavedBufferAttribute ) {

                        const data = geometryAttribute.data;
                        const stride = data.stride;
                        const offset = geometryAttribute.offset;

                        if ( data.isInstancedInterleavedBuffer ) {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );

                            }

                            if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {

                                geometry._maxInstanceCount = data.meshPerAttribute * data.count;

                            }

                        } else {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttribute( programAttribute.location + i );

                            }

                        }

                        gl.bindBuffer( gl.ARRAY_BUFFER, buffer );

                        for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                            vertexAttribPointer(
                                programAttribute.location + i,
                                size / programAttribute.locationSize,
                                type,
                                normalized,
                                stride * bytesPerElement,
                                ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,
                                integer
                            );

                        }

                    } else {

                        if ( geometryAttribute.isInstancedBufferAttribute ) {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );

                            }

                            if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {

                                geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;

                            }

                        } else {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttribute( programAttribute.location + i );

                            }

                        }

                        gl.bindBuffer( gl.ARRAY_BUFFER, buffer );

                        for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                            vertexAttribPointer(
                                programAttribute.location + i,
                                size / programAttribute.locationSize,
                                type,
                                normalized,
                                size * bytesPerElement,
                                ( size / programAttribute.locationSize ) * i * bytesPerElement,
                                integer
                            );

                        }

                    }

                } else if ( materialDefaultAttributeValues !== undefined ) {

                    const value = materialDefaultAttributeValues[ name ];

                    if ( value !== undefined ) {

                        switch ( value.length ) {

                            case 2:
                                gl.vertexAttrib2fv( programAttribute.location, value );
                                break;

                            case 3:
                                gl.vertexAttrib3fv( programAttribute.location, value );
                                break;

                            case 4:
                                gl.vertexAttrib4fv( programAttribute.location, value );
                                break;

                            default:
                                gl.vertexAttrib1fv( programAttribute.location, value );

                        }

                    }

                }

            }

        }

        disableUnusedAttributes();

    }

    function dispose() {

        reset();

        for ( const geometryId in bindingStates ) {

            const programMap = bindingStates[ geometryId ];

            for ( const programId in programMap ) {

                const stateMap = programMap[ programId ];

                for ( const wireframe in stateMap ) {

                    deleteVertexArrayObject( stateMap[ wireframe ].object );

                    delete stateMap[ wireframe ];

                }

                delete programMap[ programId ];

            }

            delete bindingStates[ geometryId ];

        }

    }

    function releaseStatesOfGeometry( geometry ) {

        if ( bindingStates[ geometry.id ] === undefined ) return;

        const programMap = bindingStates[ geometry.id ];

        for ( const programId in programMap ) {

            const stateMap = programMap[ programId ];

            for ( const wireframe in stateMap ) {

                deleteVertexArrayObject( stateMap[ wireframe ].object );

                delete stateMap[ wireframe ];

            }

            delete programMap[ programId ];

        }

        delete bindingStates[ geometry.id ];

    }

    function releaseStatesOfProgram( program ) {

        for ( const geometryId in bindingStates ) {

            const programMap = bindingStates[ geometryId ];

            if ( programMap[ program.id ] === undefined ) continue;

            const stateMap = programMap[ program.id ];

            for ( const wireframe in stateMap ) {

                deleteVertexArrayObject( stateMap[ wireframe ].object );

                delete stateMap[ wireframe ];

            }

            delete programMap[ program.id ];

        }

    }

    function reset() {

        resetDefaultState();
        forceUpdate = true;

        if ( currentState === defaultState ) return;

        currentState = defaultState;
        bindVertexArrayObject( currentState.object );

    }

    // for backward-compatibility

    function resetDefaultState() {

        defaultState.geometry = null;
        defaultState.program = null;
        defaultState.wireframe = false;

    }

    return {

        setup: setup,
        reset: reset,
        resetDefaultState: resetDefaultState,
        dispose: dispose,
        releaseStatesOfGeometry: releaseStatesOfGeometry,
        releaseStatesOfProgram: releaseStatesOfProgram,

        initAttributes: initAttributes,
        enableAttribute: enableAttribute,
        disableUnusedAttributes: disableUnusedAttributes

    };

}

setup(object: any, material: any, program: any, geometry: any, index: any): void

Parameters:

  • object any
  • material any
  • program any
  • geometry any
  • index any

Returns: void

Calls:

  • getBindingState
  • bindVertexArrayObject
  • needsUpdate
  • saveCache
  • attributes.update
  • setupVertexAttributes
  • gl.bindBuffer
  • attributes.get
Code
function setup( object, material, program, geometry, index ) {

        let updateBuffers = false;

        const state = getBindingState( geometry, program, material );

        if ( currentState !== state ) {

            currentState = state;
            bindVertexArrayObject( currentState.object );

        }

        updateBuffers = needsUpdate( object, geometry, program, index );

        if ( updateBuffers ) saveCache( object, geometry, program, index );

        if ( index !== null ) {

            attributes.update( index, gl.ELEMENT_ARRAY_BUFFER );

        }

        if ( updateBuffers || forceUpdate ) {

            forceUpdate = false;

            setupVertexAttributes( object, material, program, geometry );

            if ( index !== null ) {

                gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );

            }

        }

    }

createVertexArrayObject(): any

Returns: any

Calls:

  • gl.createVertexArray
Code
function createVertexArrayObject() {

        return gl.createVertexArray();

    }

bindVertexArrayObject(vao: any): any

Parameters:

  • vao any

Returns: any

Calls:

  • gl.bindVertexArray
Code
function bindVertexArrayObject( vao ) {

        return gl.bindVertexArray( vao );

    }

deleteVertexArrayObject(vao: any): any

Parameters:

  • vao any

Returns: any

Calls:

  • gl.deleteVertexArray
Code
function deleteVertexArrayObject( vao ) {

        return gl.deleteVertexArray( vao );

    }

getBindingState(geometry: any, program: any, material: any): any

Parameters:

  • geometry any
  • program any
  • material any

Returns: any

Calls:

  • createBindingState
  • createVertexArrayObject
Code
function getBindingState( geometry, program, material ) {

        const wireframe = ( material.wireframe === true );

        let programMap = bindingStates[ geometry.id ];

        if ( programMap === undefined ) {

            programMap = {};
            bindingStates[ geometry.id ] = programMap;

        }

        let stateMap = programMap[ program.id ];

        if ( stateMap === undefined ) {

            stateMap = {};
            programMap[ program.id ] = stateMap;

        }

        let state = stateMap[ wireframe ];

        if ( state === undefined ) {

            state = createBindingState( createVertexArrayObject() );
            stateMap[ wireframe ] = state;

        }

        return state;

    }

createBindingState(vao: any): { geometry: any; program: any; wireframe: boolean; newAttributes: number[]; enabledAttributes: number[]; attributeDivisors: number[]; object: any; attributes: {}; index: any; }

Parameters:

  • vao any

Returns: { geometry: any; program: any; wireframe: boolean; newAttributes: number[]; enabledAttributes: number[]; attributeDivisors: number[]; object: any; attributes: {}; index: any; }

Internal Comments:

// for backward compatibility on non-VAO support browser (x2)

Code
function createBindingState( vao ) {

        const newAttributes = [];
        const enabledAttributes = [];
        const attributeDivisors = [];

        for ( let i = 0; i < maxVertexAttributes; i ++ ) {

            newAttributes[ i ] = 0;
            enabledAttributes[ i ] = 0;
            attributeDivisors[ i ] = 0;

        }

        return {

            // for backward compatibility on non-VAO support browser
            geometry: null,
            program: null,
            wireframe: false,

            newAttributes: newAttributes,
            enabledAttributes: enabledAttributes,
            attributeDivisors: attributeDivisors,
            object: vao,
            attributes: {},
            index: null

        };

    }

needsUpdate(object: any, geometry: any, program: any, index: any): boolean

Parameters:

  • object any
  • geometry any
  • program any
  • index any

Returns: boolean

Calls:

  • program.getAttributes
Code
function needsUpdate( object, geometry, program, index ) {

        const cachedAttributes = currentState.attributes;
        const geometryAttributes = geometry.attributes;

        let attributesNum = 0;

        const programAttributes = program.getAttributes();

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                const cachedAttribute = cachedAttributes[ name ];
                let geometryAttribute = geometryAttributes[ name ];

                if ( geometryAttribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;

                }

                if ( cachedAttribute === undefined ) return true;

                if ( cachedAttribute.attribute !== geometryAttribute ) return true;

                if ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;

                attributesNum ++;

            }

        }

        if ( currentState.attributesNum !== attributesNum ) return true;

        if ( currentState.index !== index ) return true;

        return false;

    }

saveCache(object: any, geometry: any, program: any, index: any): void

Parameters:

  • object any
  • geometry any
  • program any
  • index any

Returns: void

Calls:

  • program.getAttributes
Code
function saveCache( object, geometry, program, index ) {

        const cache = {};
        const attributes = geometry.attributes;
        let attributesNum = 0;

        const programAttributes = program.getAttributes();

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                let attribute = attributes[ name ];

                if ( attribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;

                }

                const data = {};
                data.attribute = attribute;

                if ( attribute && attribute.data ) {

                    data.data = attribute.data;

                }

                cache[ name ] = data;

                attributesNum ++;

            }

        }

        currentState.attributes = cache;
        currentState.attributesNum = attributesNum;

        currentState.index = index;

    }

initAttributes(): void

Returns: void

Code
function initAttributes() {

        const newAttributes = currentState.newAttributes;

        for ( let i = 0, il = newAttributes.length; i < il; i ++ ) {

            newAttributes[ i ] = 0;

        }

    }

enableAttribute(attribute: any): void

Parameters:

  • attribute any

Returns: void

Calls:

  • enableAttributeAndDivisor
Code
function enableAttribute( attribute ) {

        enableAttributeAndDivisor( attribute, 0 );

    }

enableAttributeAndDivisor(attribute: any, meshPerAttribute: any): void

Parameters:

  • attribute any
  • meshPerAttribute any

Returns: void

Calls:

  • gl.enableVertexAttribArray
  • gl.vertexAttribDivisor
Code
function enableAttributeAndDivisor( attribute, meshPerAttribute ) {

        const newAttributes = currentState.newAttributes;
        const enabledAttributes = currentState.enabledAttributes;
        const attributeDivisors = currentState.attributeDivisors;

        newAttributes[ attribute ] = 1;

        if ( enabledAttributes[ attribute ] === 0 ) {

            gl.enableVertexAttribArray( attribute );
            enabledAttributes[ attribute ] = 1;

        }

        if ( attributeDivisors[ attribute ] !== meshPerAttribute ) {

            gl.vertexAttribDivisor( attribute, meshPerAttribute );
            attributeDivisors[ attribute ] = meshPerAttribute;

        }

    }

disableUnusedAttributes(): void

Returns: void

Calls:

  • gl.disableVertexAttribArray
Code
function disableUnusedAttributes() {

        const newAttributes = currentState.newAttributes;
        const enabledAttributes = currentState.enabledAttributes;

        for ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {

            if ( enabledAttributes[ i ] !== newAttributes[ i ] ) {

                gl.disableVertexAttribArray( i );
                enabledAttributes[ i ] = 0;

            }

        }

    }

vertexAttribPointer(index: any, size: any, type: any, normalized: any, stride: any, offset: any, integer: any): void

Parameters:

  • index any
  • size any
  • type any
  • normalized any
  • stride any
  • offset any
  • integer any

Returns: void

Calls:

  • gl.vertexAttribIPointer
  • gl.vertexAttribPointer
Code
function vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {

        if ( integer === true ) {

            gl.vertexAttribIPointer( index, size, type, stride, offset );

        } else {

            gl.vertexAttribPointer( index, size, type, normalized, stride, offset );

        }

    }

setupVertexAttributes(object: any, material: any, program: any, geometry: any): void

Parameters:

  • object any
  • material any
  • program any
  • geometry any

Returns: void

Calls:

  • initAttributes
  • program.getAttributes
  • attributes.get
  • enableAttributeAndDivisor
  • enableAttribute
  • gl.bindBuffer
  • vertexAttribPointer
  • gl.vertexAttrib2fv
  • gl.vertexAttrib3fv
  • gl.vertexAttrib4fv
  • gl.vertexAttrib1fv
  • disableUnusedAttributes

Internal Comments:

// TODO Attribute may not be available on context restore
// check for integer attributes (x2)

Code
function setupVertexAttributes( object, material, program, geometry ) {

        initAttributes();

        const geometryAttributes = geometry.attributes;

        const programAttributes = program.getAttributes();

        const materialDefaultAttributeValues = material.defaultAttributeValues;

        for ( const name in programAttributes ) {

            const programAttribute = programAttributes[ name ];

            if ( programAttribute.location >= 0 ) {

                let geometryAttribute = geometryAttributes[ name ];

                if ( geometryAttribute === undefined ) {

                    if ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;
                    if ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;

                }

                if ( geometryAttribute !== undefined ) {

                    const normalized = geometryAttribute.normalized;
                    const size = geometryAttribute.itemSize;

                    const attribute = attributes.get( geometryAttribute );

                    // TODO Attribute may not be available on context restore

                    if ( attribute === undefined ) continue;

                    const buffer = attribute.buffer;
                    const type = attribute.type;
                    const bytesPerElement = attribute.bytesPerElement;

                    // check for integer attributes

                    const integer = ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType );

                    if ( geometryAttribute.isInterleavedBufferAttribute ) {

                        const data = geometryAttribute.data;
                        const stride = data.stride;
                        const offset = geometryAttribute.offset;

                        if ( data.isInstancedInterleavedBuffer ) {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );

                            }

                            if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {

                                geometry._maxInstanceCount = data.meshPerAttribute * data.count;

                            }

                        } else {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttribute( programAttribute.location + i );

                            }

                        }

                        gl.bindBuffer( gl.ARRAY_BUFFER, buffer );

                        for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                            vertexAttribPointer(
                                programAttribute.location + i,
                                size / programAttribute.locationSize,
                                type,
                                normalized,
                                stride * bytesPerElement,
                                ( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,
                                integer
                            );

                        }

                    } else {

                        if ( geometryAttribute.isInstancedBufferAttribute ) {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );

                            }

                            if ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {

                                geometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;

                            }

                        } else {

                            for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                                enableAttribute( programAttribute.location + i );

                            }

                        }

                        gl.bindBuffer( gl.ARRAY_BUFFER, buffer );

                        for ( let i = 0; i < programAttribute.locationSize; i ++ ) {

                            vertexAttribPointer(
                                programAttribute.location + i,
                                size / programAttribute.locationSize,
                                type,
                                normalized,
                                size * bytesPerElement,
                                ( size / programAttribute.locationSize ) * i * bytesPerElement,
                                integer
                            );

                        }

                    }

                } else if ( materialDefaultAttributeValues !== undefined ) {

                    const value = materialDefaultAttributeValues[ name ];

                    if ( value !== undefined ) {

                        switch ( value.length ) {

                            case 2:
                                gl.vertexAttrib2fv( programAttribute.location, value );
                                break;

                            case 3:
                                gl.vertexAttrib3fv( programAttribute.location, value );
                                break;

                            case 4:
                                gl.vertexAttrib4fv( programAttribute.location, value );
                                break;

                            default:
                                gl.vertexAttrib1fv( programAttribute.location, value );

                        }

                    }

                }

            }

        }

        disableUnusedAttributes();

    }

dispose(): void

Returns: void

Calls:

  • reset
  • deleteVertexArrayObject
Code
function dispose() {

        reset();

        for ( const geometryId in bindingStates ) {

            const programMap = bindingStates[ geometryId ];

            for ( const programId in programMap ) {

                const stateMap = programMap[ programId ];

                for ( const wireframe in stateMap ) {

                    deleteVertexArrayObject( stateMap[ wireframe ].object );

                    delete stateMap[ wireframe ];

                }

                delete programMap[ programId ];

            }

            delete bindingStates[ geometryId ];

        }

    }

releaseStatesOfGeometry(geometry: any): void

Parameters:

  • geometry any

Returns: void

Calls:

  • deleteVertexArrayObject
Code
function releaseStatesOfGeometry( geometry ) {

        if ( bindingStates[ geometry.id ] === undefined ) return;

        const programMap = bindingStates[ geometry.id ];

        for ( const programId in programMap ) {

            const stateMap = programMap[ programId ];

            for ( const wireframe in stateMap ) {

                deleteVertexArrayObject( stateMap[ wireframe ].object );

                delete stateMap[ wireframe ];

            }

            delete programMap[ programId ];

        }

        delete bindingStates[ geometry.id ];

    }

releaseStatesOfProgram(program: any): void

Parameters:

  • program any

Returns: void

Calls:

  • deleteVertexArrayObject
Code
function releaseStatesOfProgram( program ) {

        for ( const geometryId in bindingStates ) {

            const programMap = bindingStates[ geometryId ];

            if ( programMap[ program.id ] === undefined ) continue;

            const stateMap = programMap[ program.id ];

            for ( const wireframe in stateMap ) {

                deleteVertexArrayObject( stateMap[ wireframe ].object );

                delete stateMap[ wireframe ];

            }

            delete programMap[ program.id ];

        }

    }

reset(): void

Returns: void

Calls:

  • resetDefaultState
  • bindVertexArrayObject
Code
function reset() {

        resetDefaultState();
        forceUpdate = true;

        if ( currentState === defaultState ) return;

        currentState = defaultState;
        bindVertexArrayObject( currentState.object );

    }

resetDefaultState(): void

Returns: void

Code
function resetDefaultState() {

        defaultState.geometry = null;
        defaultState.program = null;
        defaultState.wireframe = false;

    }

WebGLBufferRenderer(gl: any, extensions: any, info: any): void

Parameters:

  • gl any
  • extensions any
  • info any

Returns: void

Calls:

  • gl.drawArrays
  • info.update
  • gl.drawArraysInstanced
  • extensions.get
  • extension.multiDrawArraysWEBGL
  • renderInstances
  • extension.multiDrawArraysInstancedWEBGL

Internal Comments:

// (x4)

Code
function WebGLBufferRenderer( gl, extensions, info ) {

    let mode;

    function setMode( value ) {

        mode = value;

    }

    function render( start, count ) {

        gl.drawArrays( mode, start, count );

        info.update( count, mode, 1 );

    }

    function renderInstances( start, count, primcount ) {

        if ( primcount === 0 ) return;

        gl.drawArraysInstanced( 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' );
        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 );

    }

    function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );

        if ( extension === null ) {

            for ( let i = 0; i < starts.length; i ++ ) {

                renderInstances( starts[ i ], counts[ i ], primcount[ i ] );

            }

        } else {

            extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );

            let elementCount = 0;
            for ( let i = 0; i < drawCount; i ++ ) {

                elementCount += counts[ i ] * primcount[ i ];

            }

            info.update( elementCount, mode, 1 );

        }

    }

    //

    this.setMode = setMode;
    this.render = render;
    this.renderInstances = renderInstances;
    this.renderMultiDraw = renderMultiDraw;
    this.renderMultiDrawInstances = renderMultiDrawInstances;

}

setMode(value: any): void

Parameters:

  • value any

Returns: void

Code
function setMode( value ) {

        mode = value;

    }

render(start: any, count: any): void

Parameters:

  • start any
  • count any

Returns: void

Calls:

  • gl.drawArrays
  • info.update
Code
function render( start, count ) {

        gl.drawArrays( mode, start, count );

        info.update( count, mode, 1 );

    }

renderInstances(start: any, count: any, primcount: any): void

Parameters:

  • start any
  • count any
  • primcount any

Returns: void

Calls:

  • gl.drawArraysInstanced
  • info.update
Code
function renderInstances( start, count, primcount ) {

        if ( primcount === 0 ) return;

        gl.drawArraysInstanced( mode, start, count, primcount );

        info.update( count, mode, primcount );

    }

renderMultiDraw(starts: any, counts: any, drawCount: any): void

Parameters:

  • starts any
  • counts any
  • drawCount any

Returns: void

Calls:

  • extensions.get
  • extension.multiDrawArraysWEBGL
  • info.update
Code
function renderMultiDraw( starts, counts, drawCount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );
        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 );

    }

renderMultiDrawInstances(starts: any, counts: any, drawCount: any, primcount: any): void

Parameters:

  • starts any
  • counts any
  • drawCount any
  • primcount any

Returns: void

Calls:

  • extensions.get
  • renderInstances
  • extension.multiDrawArraysInstancedWEBGL
  • info.update
Code
function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );

        if ( extension === null ) {

            for ( let i = 0; i < starts.length; i ++ ) {

                renderInstances( starts[ i ], counts[ i ], primcount[ i ] );

            }

        } else {

            extension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );

            let elementCount = 0;
            for ( let i = 0; i < drawCount; i ++ ) {

                elementCount += counts[ i ] * primcount[ i ];

            }

            info.update( elementCount, mode, 1 );

        }

    }

WebGLCapabilities(gl: any, extensions: any, parameters: any, utils: any): { isWebGL2: boolean; getMaxAnisotropy: () => any; getMaxPrecision: (precision: any) => "highp" | "mediump" | "lowp"; textureFormatReadable: (textureFormat: any) => boolean; textureTypeReadable: (textureType: any) => boolean; ... 12 more ...; maxSamples: any; }

Parameters:

  • gl any
  • extensions any
  • parameters any
  • utils any

Returns: { isWebGL2: boolean; getMaxAnisotropy: () => any; getMaxPrecision: (precision: any) => "highp" | "mediump" | "lowp"; textureFormatReadable: (textureFormat: any) => boolean; textureTypeReadable: (textureType: any) => boolean; ... 12 more ...; maxSamples: any; }

Calls:

  • extensions.has
  • extensions.get
  • gl.getParameter
  • utils.convert
  • gl.getShaderPrecisionFormat
  • getMaxPrecision
  • console.warn
Code
function WebGLCapabilities( gl, extensions, parameters, utils ) {

    let maxAnisotropy;

    function getMaxAnisotropy() {

        if ( maxAnisotropy !== undefined ) return maxAnisotropy;

        if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {

            const extension = extensions.get( 'EXT_texture_filter_anisotropic' );

            maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );

        } else {

            maxAnisotropy = 0;

        }

        return maxAnisotropy;

    }

    function textureFormatReadable( textureFormat ) {

        if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {

            return false;

        }

        return true;

    }

    function textureTypeReadable( textureType ) {

        const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) );

        if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
            textureType !== FloatType && ! halfFloatSupportedByExt ) {

            return false;

        }

        return true;

    }

    function getMaxPrecision( precision ) {

        if ( precision === 'highp' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
                gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {

                return 'highp';

            }

            precision = 'mediump';

        }

        if ( precision === 'mediump' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
                gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {

                return 'mediump';

            }

        }

        return 'lowp';

    }

    let precision = parameters.precision !== undefined ? parameters.precision : 'highp';
    const maxPrecision = getMaxPrecision( precision );

    if ( maxPrecision !== precision ) {

        console.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );
        precision = maxPrecision;

    }

    const logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;
    const reversedDepthBuffer = parameters.reversedDepthBuffer === true && extensions.has( 'EXT_clip_control' );

    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( 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 maxSamples = gl.getParameter( gl.MAX_SAMPLES );

    return {

        isWebGL2: true, // keeping this for backwards compatibility

        getMaxAnisotropy: getMaxAnisotropy,
        getMaxPrecision: getMaxPrecision,

        textureFormatReadable: textureFormatReadable,
        textureTypeReadable: textureTypeReadable,

        precision: precision,
        logarithmicDepthBuffer: logarithmicDepthBuffer,
        reversedDepthBuffer: reversedDepthBuffer,

        maxTextures: maxTextures,
        maxVertexTextures: maxVertexTextures,
        maxTextureSize: maxTextureSize,
        maxCubemapSize: maxCubemapSize,

        maxAttributes: maxAttributes,
        maxVertexUniforms: maxVertexUniforms,
        maxVaryings: maxVaryings,
        maxFragmentUniforms: maxFragmentUniforms,

        vertexTextures: vertexTextures,

        maxSamples: maxSamples

    };

}

getMaxAnisotropy(): any

Returns: any

Calls:

  • extensions.has
  • extensions.get
  • gl.getParameter
Code
function getMaxAnisotropy() {

        if ( maxAnisotropy !== undefined ) return maxAnisotropy;

        if ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {

            const extension = extensions.get( 'EXT_texture_filter_anisotropic' );

            maxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );

        } else {

            maxAnisotropy = 0;

        }

        return maxAnisotropy;

    }

textureFormatReadable(textureFormat: any): boolean

Parameters:

  • textureFormat any

Returns: boolean

Calls:

  • utils.convert
  • gl.getParameter
Code
function textureFormatReadable( textureFormat ) {

        if ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {

            return false;

        }

        return true;

    }

textureTypeReadable(textureType: any): boolean

Parameters:

  • textureType any

Returns: boolean

Calls:

  • extensions.has
  • utils.convert
  • gl.getParameter
Code
function textureTypeReadable( textureType ) {

        const halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) );

        if ( textureType !== UnsignedByteType && utils.convert( textureType ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)
            textureType !== FloatType && ! halfFloatSupportedByExt ) {

            return false;

        }

        return true;

    }

getMaxPrecision(precision: any): "highp" | "mediump" | "lowp"

Parameters:

  • precision any

Returns: "highp" | "mediump" | "lowp"

Calls:

  • gl.getShaderPrecisionFormat
Code
function getMaxPrecision( precision ) {

        if ( precision === 'highp' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&
                gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {

                return 'highp';

            }

            precision = 'mediump';

        }

        if ( precision === 'mediump' ) {

            if ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&
                gl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {

                return 'mediump';

            }

        }

        return 'lowp';

    }

WebGLClipping(properties: any): void

Parameters:

  • properties any

Returns: void

Calls:

  • projectPlanes
  • properties.get
  • resetGlobalState
  • viewNormalMatrix.getNormalMatrix
  • plane.copy( planes[ i ] ).applyMatrix4
  • plane.normal.toArray

Internal Comments:

// enable state of previous frame - the clipping code has to (x2)
// run another frame in order to reset the state: (x2)
// there's no local clipping
// there's no global clipping (x3)

Code
function WebGLClipping( properties ) {

    const scope = this;

    let globalState = null,
        numGlobalPlanes = 0,
        localClippingEnabled = false,
        renderingShadows = false;

    const plane = new Plane(),
        viewNormalMatrix = new Matrix3(),

        uniform = { value: null, needsUpdate: false };

    this.uniform = uniform;
    this.numPlanes = 0;
    this.numIntersection = 0;

    this.init = function ( planes, enableLocalClipping ) {

        const enabled =
            planes.length !== 0 ||
            enableLocalClipping ||
            // enable state of previous frame - the clipping code has to
            // run another frame in order to reset the state:
            numGlobalPlanes !== 0 ||
            localClippingEnabled;

        localClippingEnabled = enableLocalClipping;

        numGlobalPlanes = planes.length;

        return enabled;

    };

    this.beginShadows = function () {

        renderingShadows = true;
        projectPlanes( null );

    };

    this.endShadows = function () {

        renderingShadows = false;

    };

    this.setGlobalState = function ( planes, camera ) {

        globalState = projectPlanes( planes, camera, 0 );

    };

    this.setState = function ( material, camera, useCache ) {

        const planes = material.clippingPlanes,
            clipIntersection = material.clipIntersection,
            clipShadows = material.clipShadows;

        const materialProperties = properties.get( material );

        if ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {

            // there's no local clipping

            if ( renderingShadows ) {

                // there's no global clipping

                projectPlanes( null );

            } else {

                resetGlobalState();

            }

        } else {

            const nGlobal = renderingShadows ? 0 : numGlobalPlanes,
                lGlobal = nGlobal * 4;

            let dstArray = materialProperties.clippingState || null;

            uniform.value = dstArray; // ensure unique state

            dstArray = projectPlanes( planes, camera, lGlobal, useCache );

            for ( let i = 0; i !== lGlobal; ++ i ) {

                dstArray[ i ] = globalState[ i ];

            }

            materialProperties.clippingState = dstArray;
            this.numIntersection = clipIntersection ? this.numPlanes : 0;
            this.numPlanes += nGlobal;

        }


    };

    function resetGlobalState() {

        if ( uniform.value !== globalState ) {

            uniform.value = globalState;
            uniform.needsUpdate = numGlobalPlanes > 0;

        }

        scope.numPlanes = numGlobalPlanes;
        scope.numIntersection = 0;

    }

    function projectPlanes( planes, camera, dstOffset, skipTransform ) {

        const nPlanes = planes !== null ? planes.length : 0;
        let dstArray = null;

        if ( nPlanes !== 0 ) {

            dstArray = uniform.value;

            if ( skipTransform !== true || dstArray === null ) {

                const flatSize = dstOffset + nPlanes * 4,
                    viewMatrix = camera.matrixWorldInverse;

                viewNormalMatrix.getNormalMatrix( viewMatrix );

                if ( dstArray === null || dstArray.length < flatSize ) {

                    dstArray = new Float32Array( flatSize );

                }

                for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {

                    plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );

                    plane.normal.toArray( dstArray, i4 );
                    dstArray[ i4 + 3 ] = plane.constant;

                }

            }

            uniform.value = dstArray;
            uniform.needsUpdate = true;

        }

        scope.numPlanes = nPlanes;
        scope.numIntersection = 0;

        return dstArray;

    }

}

resetGlobalState(): void

Returns: void

Code
function resetGlobalState() {

        if ( uniform.value !== globalState ) {

            uniform.value = globalState;
            uniform.needsUpdate = numGlobalPlanes > 0;

        }

        scope.numPlanes = numGlobalPlanes;
        scope.numIntersection = 0;

    }

projectPlanes(planes: any, camera: any, dstOffset: any, skipTransform: any): any

Parameters:

  • planes any
  • camera any
  • dstOffset any
  • skipTransform any

Returns: any

Calls:

  • viewNormalMatrix.getNormalMatrix
  • plane.copy( planes[ i ] ).applyMatrix4
  • plane.normal.toArray
Code
function projectPlanes( planes, camera, dstOffset, skipTransform ) {

        const nPlanes = planes !== null ? planes.length : 0;
        let dstArray = null;

        if ( nPlanes !== 0 ) {

            dstArray = uniform.value;

            if ( skipTransform !== true || dstArray === null ) {

                const flatSize = dstOffset + nPlanes * 4,
                    viewMatrix = camera.matrixWorldInverse;

                viewNormalMatrix.getNormalMatrix( viewMatrix );

                if ( dstArray === null || dstArray.length < flatSize ) {

                    dstArray = new Float32Array( flatSize );

                }

                for ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {

                    plane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );

                    plane.normal.toArray( dstArray, i4 );
                    dstArray[ i4 + 3 ] = plane.constant;

                }

            }

            uniform.value = dstArray;
            uniform.needsUpdate = true;

        }

        scope.numPlanes = nPlanes;
        scope.numIntersection = 0;

        return dstArray;

    }

WebGLCubeMaps(renderer: any): { get: (texture: any) => any; dispose: () => void; }

Parameters:

  • renderer any

Returns: { get: (texture: any) => any; dispose: () => void; }

Calls:

  • cubemaps.has
  • cubemaps.get
  • mapTextureMapping
  • renderTarget.fromEquirectangularTexture
  • cubemaps.set
  • texture.addEventListener
  • texture.removeEventListener
  • cubemaps.delete
  • cubemap.dispose

Internal Comments:

// image not yet ready. try the conversion next frame

Code
function WebGLCubeMaps( renderer ) {

    let cubemaps = new WeakMap();

    function mapTextureMapping( texture, mapping ) {

        if ( mapping === EquirectangularReflectionMapping ) {

            texture.mapping = CubeReflectionMapping;

        } else if ( mapping === EquirectangularRefractionMapping ) {

            texture.mapping = CubeRefractionMapping;

        }

        return texture;

    }

    function get( texture ) {

        if ( texture && texture.isTexture ) {

            const mapping = texture.mapping;

            if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {

                if ( cubemaps.has( texture ) ) {

                    const cubemap = cubemaps.get( texture ).texture;
                    return mapTextureMapping( cubemap, texture.mapping );

                } else {

                    const image = texture.image;

                    if ( image && image.height > 0 ) {

                        const renderTarget = new WebGLCubeRenderTarget( image.height );
                        renderTarget.fromEquirectangularTexture( renderer, texture );
                        cubemaps.set( texture, renderTarget );

                        texture.addEventListener( 'dispose', onTextureDispose );

                        return mapTextureMapping( renderTarget.texture, texture.mapping );

                    } else {

                        // image not yet ready. try the conversion next frame

                        return null;

                    }

                }

            }

        }

        return texture;

    }

    function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        const cubemap = cubemaps.get( texture );

        if ( cubemap !== undefined ) {

            cubemaps.delete( texture );
            cubemap.dispose();

        }

    }

    function dispose() {

        cubemaps = new WeakMap();

    }

    return {
        get: get,
        dispose: dispose
    };

}

mapTextureMapping(texture: any, mapping: any): any

Parameters:

  • texture any
  • mapping any

Returns: any

Code
function mapTextureMapping( texture, mapping ) {

        if ( mapping === EquirectangularReflectionMapping ) {

            texture.mapping = CubeReflectionMapping;

        } else if ( mapping === EquirectangularRefractionMapping ) {

            texture.mapping = CubeRefractionMapping;

        }

        return texture;

    }

get(texture: any): any

Parameters:

  • texture any

Returns: any

Calls:

  • cubemaps.has
  • cubemaps.get
  • mapTextureMapping
  • renderTarget.fromEquirectangularTexture
  • cubemaps.set
  • texture.addEventListener

Internal Comments:

// image not yet ready. try the conversion next frame

Code
function get( texture ) {

        if ( texture && texture.isTexture ) {

            const mapping = texture.mapping;

            if ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {

                if ( cubemaps.has( texture ) ) {

                    const cubemap = cubemaps.get( texture ).texture;
                    return mapTextureMapping( cubemap, texture.mapping );

                } else {

                    const image = texture.image;

                    if ( image && image.height > 0 ) {

                        const renderTarget = new WebGLCubeRenderTarget( image.height );
                        renderTarget.fromEquirectangularTexture( renderer, texture );
                        cubemaps.set( texture, renderTarget );

                        texture.addEventListener( 'dispose', onTextureDispose );

                        return mapTextureMapping( renderTarget.texture, texture.mapping );

                    } else {

                        // image not yet ready. try the conversion next frame

                        return null;

                    }

                }

            }

        }

        return texture;

    }

onTextureDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • texture.removeEventListener
  • cubemaps.get
  • cubemaps.delete
  • cubemap.dispose
Code
function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        const cubemap = cubemaps.get( texture );

        if ( cubemap !== undefined ) {

            cubemaps.delete( texture );
            cubemap.dispose();

        }

    }

dispose(): void

Returns: void

Code
function dispose() {

        cubemaps = new WeakMap();

    }

PMREMGenerator.fromScene(scene: Scene, sigma: number, near: number, far: number, options: { size?: number; renderTarget?: Vector3; }): WebGLRenderTarget

JSDoc:

/**
     * Generates a PMREM from a supplied Scene, which can be faster than using an
     * image if networking bandwidth is low. Optional sigma specifies a blur radius
     * in radians to be applied to the scene before PMREM generation. Optional near
     * and far planes ensure the scene is rendered in its entirety.
     *
     * @param {Scene} scene - The scene to be captured.
     * @param {number} [sigma=0] - The blur radius in radians.
     * @param {number} [near=0.1] - The near plane distance.
     * @param {number} [far=100] - The far plane distance.
     * @param {Object} [options={}] - The configuration options.
     * @param {number} [options.size=256] - The texture size of the PMREM.
     * @param {Vector3} [options.renderTarget=origin] - The position of the internal cube camera that renders the scene.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */

Parameters:

  • scene Scene
  • sigma number
  • near number
  • far number
  • options { size?: number; renderTarget?: Vector3; }

Returns: WebGLRenderTarget

Calls:

  • this._renderer.getRenderTarget
  • this._renderer.getActiveCubeFace
  • this._renderer.getActiveMipmapLevel
  • this._setSize
  • this._allocateTargets
  • this._sceneToCubeUV
  • this._blur
  • this._applyPMREM
  • this._cleanup
Code
fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) {

        const {
            size = 256,
            position = _origin,
        } = options;

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        this._setSize( size );

        const cubeUVRenderTarget = this._allocateTargets();
        cubeUVRenderTarget.depthBuffer = true;

        this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position );

        if ( sigma > 0 ) {

            this._blur( cubeUVRenderTarget, 0, 0, sigma );

        }

        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }

PMREMGenerator.fromEquirectangular(equirectangular: Texture, renderTarget: WebGLRenderTarget): WebGLRenderTarget

JSDoc:

/**
     * Generates a PMREM from an equirectangular texture, which can be either LDR
     * or HDR. The ideal input image size is 1k (1024 x 512),
     * as this matches best with the 256 x 256 cubemap output.
     *
     * @param {Texture} equirectangular - The equirectangular texture to be converted.
     * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */

Parameters:

  • equirectangular Texture
  • renderTarget WebGLRenderTarget

Returns: WebGLRenderTarget

Calls:

  • this._fromTexture
Code
fromEquirectangular( equirectangular, renderTarget = null ) {

        return this._fromTexture( equirectangular, renderTarget );

    }

PMREMGenerator.fromCubemap(cubemap: Texture, renderTarget: WebGLRenderTarget): WebGLRenderTarget

JSDoc:

/**
     * Generates a PMREM from an cubemap texture, which can be either LDR
     * or HDR. The ideal input cube size is 256 x 256,
     * as this matches best with the 256 x 256 cubemap output.
     *
     * @param {Texture} cubemap - The cubemap texture to be converted.
     * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */

Parameters:

  • cubemap Texture
  • renderTarget WebGLRenderTarget

Returns: WebGLRenderTarget

Calls:

  • this._fromTexture
Code
fromCubemap( cubemap, renderTarget = null ) {

        return this._fromTexture( cubemap, renderTarget );

    }

PMREMGenerator.compileCubemapShader(): void

JSDoc:

/**
     * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
     * your texture's network fetch for increased concurrency.
     */

Returns: void

Calls:

  • _getCubemapMaterial
  • this._compileMaterial
Code
compileCubemapShader() {

        if ( this._cubemapMaterial === null ) {

            this._cubemapMaterial = _getCubemapMaterial();
            this._compileMaterial( this._cubemapMaterial );

        }

    }

PMREMGenerator.compileEquirectangularShader(): void

JSDoc:

/**
     * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
     * your texture's network fetch for increased concurrency.
     */

Returns: void

Calls:

  • _getEquirectMaterial
  • this._compileMaterial
Code
compileEquirectangularShader() {

        if ( this._equirectMaterial === null ) {

            this._equirectMaterial = _getEquirectMaterial();
            this._compileMaterial( this._equirectMaterial );

        }

    }

PMREMGenerator.dispose(): void

JSDoc:

/**
     * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
     * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
     * one of them will cause any others to also become unusable.
     */

Returns: void

Calls:

  • this._dispose
  • this._cubemapMaterial.dispose
  • this._equirectMaterial.dispose
Code
dispose() {

        this._dispose();

        if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
        if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();

    }

PMREMGenerator._setSize(cubeSize: any): void

Parameters:

  • cubeSize any

Returns: void

Calls:

  • Math.floor
  • Math.log2
  • Math.pow
Code
_setSize( cubeSize ) {

        this._lodMax = Math.floor( Math.log2( cubeSize ) );
        this._cubeSize = Math.pow( 2, this._lodMax );

    }

PMREMGenerator._dispose(): void

Returns: void

Calls:

  • this._blurMaterial.dispose
  • this._pingPongRenderTarget.dispose
  • this._lodPlanes[ i ].dispose
Code
_dispose() {

        if ( this._blurMaterial !== null ) this._blurMaterial.dispose();

        if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();

        for ( let i = 0; i < this._lodPlanes.length; i ++ ) {

            this._lodPlanes[ i ].dispose();

        }

    }

PMREMGenerator._cleanup(outputTarget: any): void

Parameters:

  • outputTarget any

Returns: void

Calls:

  • this._renderer.setRenderTarget
  • _setViewport
Code
_cleanup( outputTarget ) {

        this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
        this._renderer.xr.enabled = _oldXrEnabled;

        outputTarget.scissorTest = false;
        _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );

    }

PMREMGenerator._fromTexture(texture: any, renderTarget: any): any

Parameters:

  • texture any
  • renderTarget any

Returns: any

Calls:

  • this._setSize
  • this._renderer.getRenderTarget
  • this._renderer.getActiveCubeFace
  • this._renderer.getActiveMipmapLevel
  • this._allocateTargets
  • this._textureToCubeUV
  • this._applyPMREM
  • this._cleanup
Code
_fromTexture( texture, renderTarget ) {

        if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {

            this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );

        } else { // Equirectangular

            this._setSize( texture.image.width / 4 );

        }

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        const cubeUVRenderTarget = renderTarget || this._allocateTargets();
        this._textureToCubeUV( texture, cubeUVRenderTarget );
        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }

PMREMGenerator._allocateTargets(): WebGLRenderTarget

Returns: WebGLRenderTarget

Calls:

  • Math.max
  • _createRenderTarget
  • this._dispose
  • _createPlanes
  • _getBlurShader
Code
_allocateTargets() {

        const width = 3 * Math.max( this._cubeSize, 16 * 7 );
        const height = 4 * this._cubeSize;

        const params = {
            magFilter: LinearFilter,
            minFilter: LinearFilter,
            generateMipmaps: false,
            type: HalfFloatType,
            format: RGBAFormat,
            colorSpace: LinearSRGBColorSpace,
            depthBuffer: false
        };

        const cubeUVRenderTarget = _createRenderTarget( width, height, params );

        if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {

            if ( this._pingPongRenderTarget !== null ) {

                this._dispose();

            }

            this._pingPongRenderTarget = _createRenderTarget( width, height, params );

            const { _lodMax } = this;
            ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );

            this._blurMaterial = _getBlurShader( _lodMax, width, height );

        }

        return cubeUVRenderTarget;

    }

PMREMGenerator._compileMaterial(material: any): void

Parameters:

  • material any

Returns: void

Calls:

  • this._renderer.compile
Code
_compileMaterial( material ) {

        const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
        this._renderer.compile( tmpMesh, _flatCamera );

    }

PMREMGenerator._sceneToCubeUV(scene: any, near: any, far: any, cubeUVRenderTarget: any, position: any): void

Parameters:

  • scene any
  • near any
  • far any
  • cubeUVRenderTarget any
  • position any

Returns: void

Calls:

  • renderer.getClearColor
  • renderer.state.buffers.depth.getReversed
  • renderer.setRenderTarget
  • renderer.clearDepth
  • backgroundMaterial.color.copy
  • cubeCamera.up.set
  • cubeCamera.position.set
  • cubeCamera.lookAt
  • _setViewport
  • renderer.render
  • backgroundBox.geometry.dispose
  • backgroundBox.material.dispose

Internal Comments:

// https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812 (x2)

Code
_sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ) {

        const fov = 90;
        const aspect = 1;
        const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
        const upSign = [ 1, -1, 1, 1, 1, 1 ];
        const forwardSign = [ 1, 1, 1, -1, -1, -1 ];
        const renderer = this._renderer;

        const originalAutoClear = renderer.autoClear;
        const toneMapping = renderer.toneMapping;
        renderer.getClearColor( _clearColor );

        renderer.toneMapping = NoToneMapping;
        renderer.autoClear = false;

        // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812
        const reversedDepthBuffer = renderer.state.buffers.depth.getReversed();

        if ( reversedDepthBuffer ) {

            renderer.setRenderTarget( cubeUVRenderTarget );
            renderer.clearDepth();
            renderer.setRenderTarget( null );

        }

        const backgroundMaterial = new MeshBasicMaterial( {
            name: 'PMREM.Background',
            side: BackSide,
            depthWrite: false,
            depthTest: false,
        } );

        const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );

        let useSolidColor = false;
        const background = scene.background;

        if ( background ) {

            if ( background.isColor ) {

                backgroundMaterial.color.copy( background );
                scene.background = null;
                useSolidColor = true;

            }

        } else {

            backgroundMaterial.color.copy( _clearColor );
            useSolidColor = true;

        }

        for ( let i = 0; i < 6; i ++ ) {

            const col = i % 3;

            if ( col === 0 ) {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x + forwardSign[ i ], position.y, position.z );

            } else if ( col === 1 ) {

                cubeCamera.up.set( 0, 0, upSign[ i ] );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y + forwardSign[ i ], position.z );


            } else {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y, position.z + forwardSign[ i ] );

            }

            const size = this._cubeSize;

            _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );

            renderer.setRenderTarget( cubeUVRenderTarget );

            if ( useSolidColor ) {

                renderer.render( backgroundBox, cubeCamera );

            }

            renderer.render( scene, cubeCamera );

        }

        backgroundBox.geometry.dispose();
        backgroundBox.material.dispose();

        renderer.toneMapping = toneMapping;
        renderer.autoClear = originalAutoClear;
        scene.background = background;

    }

PMREMGenerator._textureToCubeUV(texture: any, cubeUVRenderTarget: any): void

Parameters:

  • texture any
  • cubeUVRenderTarget any

Returns: void

Calls:

  • _getCubemapMaterial
  • _getEquirectMaterial
  • _setViewport
  • renderer.setRenderTarget
  • renderer.render
Code
_textureToCubeUV( texture, cubeUVRenderTarget ) {

        const renderer = this._renderer;

        const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );

        if ( isCubeTexture ) {

            if ( this._cubemapMaterial === null ) {

                this._cubemapMaterial = _getCubemapMaterial();

            }

            this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? -1 : 1;

        } else {

            if ( this._equirectMaterial === null ) {

                this._equirectMaterial = _getEquirectMaterial();

            }

        }

        const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
        const mesh = new Mesh( this._lodPlanes[ 0 ], material );

        const uniforms = material.uniforms;

        uniforms[ 'envMap' ].value = texture;

        const size = this._cubeSize;

        _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );

        renderer.setRenderTarget( cubeUVRenderTarget );
        renderer.render( mesh, _flatCamera );

    }

PMREMGenerator._applyPMREM(cubeUVRenderTarget: any): void

Parameters:

  • cubeUVRenderTarget any

Returns: void

Calls:

  • Math.sqrt
  • this._blur
Code
_applyPMREM( cubeUVRenderTarget ) {

        const renderer = this._renderer;
        const autoClear = renderer.autoClear;
        renderer.autoClear = false;
        const n = this._lodPlanes.length;

        for ( let i = 1; i < n; i ++ ) {

            const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );

            const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];

            this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );

        }

        renderer.autoClear = autoClear;

    }

PMREMGenerator._blur(cubeUVRenderTarget: WebGLRenderTarget, lodIn: number, lodOut: number, sigma: number, poleAxis: Vector3): void

JSDoc:

/**
     * This is a two-pass Gaussian blur for a cubemap. Normally this is done
     * vertically and horizontally, but this breaks down on a cube. Here we apply
     * the blur latitudinally (around the poles), and then longitudinally (towards
     * the poles) to approximate the orthogonally-separable blur. It is least
     * accurate at the poles, but still does a decent job.
     *
     * @private
     * @param {WebGLRenderTarget} cubeUVRenderTarget
     * @param {number} lodIn
     * @param {number} lodOut
     * @param {number} sigma
     * @param {Vector3} [poleAxis]
     */

Parameters:

  • cubeUVRenderTarget WebGLRenderTarget
  • lodIn number
  • lodOut number
  • sigma number
  • poleAxis Vector3

Returns: void

Calls:

  • this._halfBlur
Code
_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {

        const pingPongRenderTarget = this._pingPongRenderTarget;

        this._halfBlur(
            cubeUVRenderTarget,
            pingPongRenderTarget,
            lodIn,
            lodOut,
            sigma,
            'latitudinal',
            poleAxis );

        this._halfBlur(
            pingPongRenderTarget,
            cubeUVRenderTarget,
            lodOut,
            lodOut,
            sigma,
            'longitudinal',
            poleAxis );

    }

PMREMGenerator._halfBlur(targetIn: any, targetOut: any, lodIn: any, lodOut: any, sigmaRadians: any, direction: any, poleAxis: any): void

Parameters:

  • targetIn any
  • targetOut any
  • lodIn any
  • lodOut any
  • sigmaRadians any
  • direction any
  • poleAxis any

Returns: void

Calls:

  • console.error
  • isFinite
  • Math.floor
  • console.warn
  • Math.exp
  • weights.push
  • _setViewport
  • renderer.setRenderTarget
  • renderer.render

Internal Comments:

// Number of standard deviations at which to cut off the discrete approximation. (x2)

Code
_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {

        const renderer = this._renderer;
        const blurMaterial = this._blurMaterial;

        if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {

            console.error(
                'blur direction must be either latitudinal or longitudinal!' );

        }

        // Number of standard deviations at which to cut off the discrete approximation.
        const STANDARD_DEVIATIONS = 3;

        const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
        const blurUniforms = blurMaterial.uniforms;

        const pixels = this._sizeLods[ lodIn ] - 1;
        const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
        const sigmaPixels = sigmaRadians / radiansPerPixel;
        const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;

        if ( samples > MAX_SAMPLES ) {

            console.warn( `sigmaRadians, ${
                sigmaRadians}, is too large and will clip, as it requested ${
                samples} samples when the maximum is set to ${MAX_SAMPLES}` );

        }

        const weights = [];
        let sum = 0;

        for ( let i = 0; i < MAX_SAMPLES; ++ i ) {

            const x = i / sigmaPixels;
            const weight = Math.exp( - x * x / 2 );
            weights.push( weight );

            if ( i === 0 ) {

                sum += weight;

            } else if ( i < samples ) {

                sum += 2 * weight;

            }

        }

        for ( let i = 0; i < weights.length; i ++ ) {

            weights[ i ] = weights[ i ] / sum;

        }

        blurUniforms[ 'envMap' ].value = targetIn.texture;
        blurUniforms[ 'samples' ].value = samples;
        blurUniforms[ 'weights' ].value = weights;
        blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';

        if ( poleAxis ) {

            blurUniforms[ 'poleAxis' ].value = poleAxis;

        }

        const { _lodMax } = this;
        blurUniforms[ 'dTheta' ].value = radiansPerPixel;
        blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;

        const outputSize = this._sizeLods[ lodOut ];
        const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
        const y = 4 * ( this._cubeSize - outputSize );

        _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
        renderer.setRenderTarget( targetOut );
        renderer.render( blurMesh, _flatCamera );

    }

_createPlanes(lodMax: any): { lodPlanes: BufferGeometry[]; sizeLods: number[]; sigmas: number[]; }

Parameters:

  • lodMax any

Returns: { lodPlanes: BufferGeometry[]; sizeLods: number[]; sigmas: number[]; }

Calls:

  • Math.pow
  • sizeLods.push
  • sigmas.push
  • position.set
  • uv.set
  • faceIndex.set
  • planes.setAttribute
  • lodPlanes.push
Code
function _createPlanes( lodMax ) {

    const lodPlanes = [];
    const sizeLods = [];
    const sigmas = [];

    let lod = lodMax;

    const totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;

    for ( let i = 0; i < totalLods; i ++ ) {

        const sizeLod = Math.pow( 2, lod );
        sizeLods.push( sizeLod );
        let sigma = 1.0 / sizeLod;

        if ( i > lodMax - LOD_MIN ) {

            sigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];

        } else if ( i === 0 ) {

            sigma = 0;

        }

        sigmas.push( sigma );

        const texelSize = 1.0 / ( sizeLod - 2 );
        const min = - texelSize;
        const max = 1 + texelSize;
        const uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];

        const cubeFaces = 6;
        const vertices = 6;
        const positionSize = 3;
        const uvSize = 2;
        const faceIndexSize = 1;

        const position = new Float32Array( positionSize * vertices * cubeFaces );
        const uv = new Float32Array( uvSize * vertices * cubeFaces );
        const faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );

        for ( let face = 0; face < cubeFaces; face ++ ) {

            const x = ( face % 3 ) * 2 / 3 - 1;
            const y = face > 2 ? 0 : -1;
            const coordinates = [
                x, y, 0,
                x + 2 / 3, y, 0,
                x + 2 / 3, y + 1, 0,
                x, y, 0,
                x + 2 / 3, y + 1, 0,
                x, y + 1, 0
            ];
            position.set( coordinates, positionSize * vertices * face );
            uv.set( uv1, uvSize * vertices * face );
            const fill = [ face, face, face, face, face, face ];
            faceIndex.set( fill, faceIndexSize * vertices * face );

        }

        const planes = new BufferGeometry();
        planes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );
        planes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );
        planes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );
        lodPlanes.push( planes );

        if ( lod > LOD_MIN ) {

            lod --;

        }

    }

    return { lodPlanes, sizeLods, sigmas };

}

_createRenderTarget(width: any, height: any, params: any): WebGLRenderTarget

Parameters:

  • width any
  • height any
  • params any

Returns: WebGLRenderTarget

Code
function _createRenderTarget( width, height, params ) {

    const cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );
    cubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;
    cubeUVRenderTarget.texture.name = 'PMREM.cubeUv';
    cubeUVRenderTarget.scissorTest = true;
    return cubeUVRenderTarget;

}

_setViewport(target: any, x: any, y: any, width: any, height: any): void

Parameters:

  • target any
  • x any
  • y any
  • width any
  • height any

Returns: void

Calls:

  • target.viewport.set
  • target.scissor.set
Code
function _setViewport( target, x, y, width, height ) {

    target.viewport.set( x, y, width, height );
    target.scissor.set( x, y, width, height );

}

_getBlurShader(lodMax: any, width: any, height: any): ShaderMaterial

Parameters:

  • lodMax any
  • width any
  • height any

Returns: ShaderMaterial

Calls:

  • _getCommonVertexShader
Code
function _getBlurShader( lodMax, width, height ) {

    const weights = new Float32Array( MAX_SAMPLES );
    const poleAxis = new Vector3( 0, 1, 0 );
    const shaderMaterial = new ShaderMaterial( {

        name: 'SphericalGaussianBlur',

        defines: {
            'n': MAX_SAMPLES,
            'CUBEUV_TEXEL_WIDTH': 1.0 / width,
            'CUBEUV_TEXEL_HEIGHT': 1.0 / height,
            'CUBEUV_MAX_MIP': `${lodMax}.0`,
        },

        uniforms: {
            'envMap': { value: null },
            'samples': { value: 1 },
            'weights': { value: weights },
            'latitudinal': { value: false },
            'dTheta': { value: 0 },
            'mipInt': { value: 0 },
            'poleAxis': { value: poleAxis }
        },

        vertexShader: _getCommonVertexShader(),

        fragmentShader: /* glsl */`

            precision mediump float;
            precision mediump int;

            varying vec3 vOutputDirection;

            uniform sampler2D envMap;
            uniform int samples;
            uniform float weights[ n ];
            uniform bool latitudinal;
            uniform float dTheta;
            uniform float mipInt;
            uniform vec3 poleAxis;

            #define ENVMAP_TYPE_CUBE_UV
            #include <cube_uv_reflection_fragment>

            vec3 getSample( float theta, vec3 axis ) {

                float cosTheta = cos( theta );
                // Rodrigues' axis-angle rotation
                vec3 sampleDirection = vOutputDirection * cosTheta
                    + cross( axis, vOutputDirection ) * sin( theta )
                    + axis * dot( axis, vOutputDirection ) * ( 1.0 - cosTheta );

                return bilinearCubeUV( envMap, sampleDirection, mipInt );

            }

            void main() {

                vec3 axis = latitudinal ? poleAxis : cross( poleAxis, vOutputDirection );

                if ( all( equal( axis, vec3( 0.0 ) ) ) ) {

                    axis = vec3( vOutputDirection.z, 0.0, - vOutputDirection.x );

                }

                axis = normalize( axis );

                gl_FragColor = vec4( 0.0, 0.0, 0.0, 1.0 );
                gl_FragColor.rgb += weights[ 0 ] * getSample( 0.0, axis );

                for ( int i = 1; i < n; i++ ) {

                    if ( i >= samples ) {

                        break;

                    }

                    float theta = dTheta * float( i );
                    gl_FragColor.rgb += weights[ i ] * getSample( -1.0 * theta, axis );
                    gl_FragColor.rgb += weights[ i ] * getSample( theta, axis );

                }

            }
        `,

        blending: NoBlending,
        depthTest: false,
        depthWrite: false

    } );

    return shaderMaterial;

}

_getEquirectMaterial(): ShaderMaterial

Returns: ShaderMaterial

Calls:

  • _getCommonVertexShader
Code
function _getEquirectMaterial() {

    return new ShaderMaterial( {

        name: 'EquirectangularToCubeUV',

        uniforms: {
            'envMap': { value: null }
        },

        vertexShader: _getCommonVertexShader(),

        fragmentShader: /* glsl */`

            precision mediump float;
            precision mediump int;

            varying vec3 vOutputDirection;

            uniform sampler2D envMap;

            #include <common>

            void main() {

                vec3 outputDirection = normalize( vOutputDirection );
                vec2 uv = equirectUv( outputDirection );

                gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 );

            }
        `,

        blending: NoBlending,
        depthTest: false,
        depthWrite: false

    } );

}

_getCubemapMaterial(): ShaderMaterial

Returns: ShaderMaterial

Calls:

  • _getCommonVertexShader
Code
function _getCubemapMaterial() {

    return new ShaderMaterial( {

        name: 'CubemapToCubeUV',

        uniforms: {
            'envMap': { value: null },
            'flipEnvMap': { value: -1 }
        },

        vertexShader: _getCommonVertexShader(),

        fragmentShader: /* glsl */`

            precision mediump float;
            precision mediump int;

            uniform float flipEnvMap;

            varying vec3 vOutputDirection;

            uniform samplerCube envMap;

            void main() {

                gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) );

            }
        `,

        blending: NoBlending,
        depthTest: false,
        depthWrite: false

    } );

}

_getCommonVertexShader(): string

Returns: string

Code
function _getCommonVertexShader() {

    return /* glsl */`

        precision mediump float;
        precision mediump int;

        attribute float faceIndex;

        varying vec3 vOutputDirection;

        // RH coordinate system; PMREM face-indexing convention
        vec3 getDirection( vec2 uv, float face ) {

            uv = 2.0 * uv - 1.0;

            vec3 direction = vec3( uv, 1.0 );

            if ( face == 0.0 ) {

                direction = direction.zyx; // ( 1, v, u ) pos x

            } else if ( face == 1.0 ) {

                direction = direction.xzy;
                direction.xz *= -1.0; // ( -u, 1, -v ) pos y

            } else if ( face == 2.0 ) {

                direction.x *= -1.0; // ( -u, v, 1 ) pos z

            } else if ( face == 3.0 ) {

                direction = direction.zyx;
                direction.xz *= -1.0; // ( -1, v, -u ) neg x

            } else if ( face == 4.0 ) {

                direction = direction.xzy;
                direction.xy *= -1.0; // ( -u, -1, v ) neg y

            } else if ( face == 5.0 ) {

                direction.z *= -1.0; // ( u, v, -1 ) neg z

            }

            return direction;

        }

        void main() {

            vOutputDirection = getDirection( uv, faceIndex );
            gl_Position = vec4( position, 1.0 );

        }
    `;

}

WebGLCubeUVMaps(renderer: any): { get: (texture: any) => any; dispose: () => void; }

Parameters:

  • renderer any

Returns: { get: (texture: any) => any; dispose: () => void; }

Calls:

  • cubeUVmaps.get
  • pmremGenerator.fromEquirectangular
  • pmremGenerator.fromCubemap
  • cubeUVmaps.set
  • isCubeTextureComplete
  • texture.addEventListener
  • texture.removeEventListener
  • cubeUVmaps.delete
  • cubemapUV.dispose
  • pmremGenerator.dispose

Internal Comments:

// equirect/cube map to cubeUV conversion
// image not yet ready. try the conversion next frame

Code
function WebGLCubeUVMaps( renderer ) {

    let cubeUVmaps = new WeakMap();

    let pmremGenerator = null;

    function get( texture ) {

        if ( texture && texture.isTexture ) {

            const mapping = texture.mapping;

            const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );
            const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );

            // equirect/cube map to cubeUV conversion

            if ( isEquirectMap || isCubeMap ) {

                let renderTarget = cubeUVmaps.get( texture );

                const currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0;

                if ( texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion ) {

                    if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );

                    renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );
                    renderTarget.texture.pmremVersion = texture.pmremVersion;

                    cubeUVmaps.set( texture, renderTarget );

                    return renderTarget.texture;

                } else {

                    if ( renderTarget !== undefined ) {

                        return renderTarget.texture;

                    } else {

                        const image = texture.image;

                        if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {

                            if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );

                            renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
                            renderTarget.texture.pmremVersion = texture.pmremVersion;

                            cubeUVmaps.set( texture, renderTarget );

                            texture.addEventListener( 'dispose', onTextureDispose );

                            return renderTarget.texture;

                        } else {

                            // image not yet ready. try the conversion next frame

                            return null;

                        }

                    }

                }

            }

        }

        return texture;

    }

    function isCubeTextureComplete( image ) {

        let count = 0;
        const length = 6;

        for ( let i = 0; i < length; i ++ ) {

            if ( image[ i ] !== undefined ) count ++;

        }

        return count === length;


    }

    function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        const cubemapUV = cubeUVmaps.get( texture );

        if ( cubemapUV !== undefined ) {

            cubeUVmaps.delete( texture );
            cubemapUV.dispose();

        }

    }

    function dispose() {

        cubeUVmaps = new WeakMap();

        if ( pmremGenerator !== null ) {

            pmremGenerator.dispose();
            pmremGenerator = null;

        }

    }

    return {
        get: get,
        dispose: dispose
    };

}

get(texture: any): any

Parameters:

  • texture any

Returns: any

Calls:

  • cubeUVmaps.get
  • pmremGenerator.fromEquirectangular
  • pmremGenerator.fromCubemap
  • cubeUVmaps.set
  • isCubeTextureComplete
  • texture.addEventListener

Internal Comments:

// equirect/cube map to cubeUV conversion
// image not yet ready. try the conversion next frame

Code
function get( texture ) {

        if ( texture && texture.isTexture ) {

            const mapping = texture.mapping;

            const isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );
            const isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );

            // equirect/cube map to cubeUV conversion

            if ( isEquirectMap || isCubeMap ) {

                let renderTarget = cubeUVmaps.get( texture );

                const currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0;

                if ( texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion ) {

                    if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );

                    renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );
                    renderTarget.texture.pmremVersion = texture.pmremVersion;

                    cubeUVmaps.set( texture, renderTarget );

                    return renderTarget.texture;

                } else {

                    if ( renderTarget !== undefined ) {

                        return renderTarget.texture;

                    } else {

                        const image = texture.image;

                        if ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {

                            if ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );

                            renderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );
                            renderTarget.texture.pmremVersion = texture.pmremVersion;

                            cubeUVmaps.set( texture, renderTarget );

                            texture.addEventListener( 'dispose', onTextureDispose );

                            return renderTarget.texture;

                        } else {

                            // image not yet ready. try the conversion next frame

                            return null;

                        }

                    }

                }

            }

        }

        return texture;

    }

isCubeTextureComplete(image: any): boolean

Parameters:

  • image any

Returns: boolean

Code
function isCubeTextureComplete( image ) {

        let count = 0;
        const length = 6;

        for ( let i = 0; i < length; i ++ ) {

            if ( image[ i ] !== undefined ) count ++;

        }

        return count === length;


    }

onTextureDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • texture.removeEventListener
  • cubeUVmaps.get
  • cubeUVmaps.delete
  • cubemapUV.dispose
Code
function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        const cubemapUV = cubeUVmaps.get( texture );

        if ( cubemapUV !== undefined ) {

            cubeUVmaps.delete( texture );
            cubemapUV.dispose();

        }

    }

dispose(): void

Returns: void

Calls:

  • pmremGenerator.dispose
Code
function dispose() {

        cubeUVmaps = new WeakMap();

        if ( pmremGenerator !== null ) {

            pmremGenerator.dispose();
            pmremGenerator = null;

        }

    }

WebGLExtensions(gl: any): { has: (name: any) => boolean; init: () => void; get: (name: any) => any; }

Parameters:

  • gl any

Returns: { has: (name: any) => boolean; init: () => void; get: (name: any) => any; }

Calls:

  • gl.getExtension
  • getExtension
  • warnOnce (from ./three.core.js)
Code
function WebGLExtensions( gl ) {

    const extensions = {};

    function getExtension( name ) {

        if ( extensions[ name ] !== undefined ) {

            return extensions[ name ];

        }

        let extension;

        switch ( name ) {

            case 'WEBGL_depth_texture':
                extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
                break;

            case 'EXT_texture_filter_anisotropic':
                extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
                break;

            case 'WEBGL_compressed_texture_s3tc':
                extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
                break;

            case 'WEBGL_compressed_texture_pvrtc':
                extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
                break;

            default:
                extension = gl.getExtension( name );

        }

        extensions[ name ] = extension;

        return extension;

    }

    return {

        has: function ( name ) {

            return getExtension( name ) !== null;

        },

        init: function () {

            getExtension( 'EXT_color_buffer_float' );
            getExtension( 'WEBGL_clip_cull_distance' );
            getExtension( 'OES_texture_float_linear' );
            getExtension( 'EXT_color_buffer_half_float' );
            getExtension( 'WEBGL_multisampled_render_to_texture' );
            getExtension( 'WEBGL_render_shared_exponent' );

        },

        get: function ( name ) {

            const extension = getExtension( name );

            if ( extension === null ) {

                warnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );

            }

            return extension;

        }

    };

}

getExtension(name: any): any

Parameters:

  • name any

Returns: any

Calls:

  • gl.getExtension
Code
function getExtension( name ) {

        if ( extensions[ name ] !== undefined ) {

            return extensions[ name ];

        }

        let extension;

        switch ( name ) {

            case 'WEBGL_depth_texture':
                extension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );
                break;

            case 'EXT_texture_filter_anisotropic':
                extension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );
                break;

            case 'WEBGL_compressed_texture_s3tc':
                extension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );
                break;

            case 'WEBGL_compressed_texture_pvrtc':
                extension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );
                break;

            default:
                extension = gl.getExtension( name );

        }

        extensions[ name ] = extension;

        return extension;

    }

has(name: any): boolean

Parameters:

  • name any

Returns: boolean

Calls:

  • getExtension
Code
function ( name ) {

            return getExtension( name ) !== null;

        }

init(): void

Returns: void

Calls:

  • getExtension
Code
function () {

            getExtension( 'EXT_color_buffer_float' );
            getExtension( 'WEBGL_clip_cull_distance' );
            getExtension( 'OES_texture_float_linear' );
            getExtension( 'EXT_color_buffer_half_float' );
            getExtension( 'WEBGL_multisampled_render_to_texture' );
            getExtension( 'WEBGL_render_shared_exponent' );

        }

get(name: any): any

Parameters:

  • name any

Returns: any

Calls:

  • getExtension
  • warnOnce (from ./three.core.js)
Code
function ( name ) {

            const extension = getExtension( name );

            if ( extension === null ) {

                warnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );

            }

            return extension;

        }

has(name: any): boolean

Parameters:

  • name any

Returns: boolean

Calls:

  • getExtension
Code
function ( name ) {

            return getExtension( name ) !== null;

        }

init(): void

Returns: void

Calls:

  • getExtension
Code
function () {

            getExtension( 'EXT_color_buffer_float' );
            getExtension( 'WEBGL_clip_cull_distance' );
            getExtension( 'OES_texture_float_linear' );
            getExtension( 'EXT_color_buffer_half_float' );
            getExtension( 'WEBGL_multisampled_render_to_texture' );
            getExtension( 'WEBGL_render_shared_exponent' );

        }

get(name: any): any

Parameters:

  • name any

Returns: any

Calls:

  • getExtension
  • warnOnce (from ./three.core.js)
Code
function ( name ) {

            const extension = getExtension( name );

            if ( extension === null ) {

                warnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );

            }

            return extension;

        }

WebGLGeometries(gl: any, attributes: any, info: any, bindingStates: any): { get: (object: any, geometry: any) => any; update: (geometry: any) => void; getWireframeAttribute: (geometry: any) => any; }

Parameters:

  • gl any
  • attributes any
  • info any
  • bindingStates any

Returns: { get: (object: any, geometry: any) => any; update: (geometry: any) => void; getWireframeAttribute: (geometry: any) => any; }

Calls:

  • attributes.remove
  • geometry.removeEventListener
  • wireframeAttributes.get
  • wireframeAttributes.delete
  • bindingStates.releaseStatesOfGeometry
  • geometry.addEventListener
  • attributes.update
  • indices.push
  • arrayNeedsUint32 (from ./three.core.js)
  • wireframeAttributes.set
  • updateWireframeAttribute

Internal Comments:

// (x11)
// Updating index buffer in VAO now. See WebGLBindingStates.
// Updating index buffer in VAO now. See WebGLBindingStates (x2)
// if the attribute is obsolete, create a new one

Code
function WebGLGeometries( gl, attributes, info, bindingStates ) {

    const geometries = {};
    const wireframeAttributes = new WeakMap();

    function onGeometryDispose( event ) {

        const geometry = event.target;

        if ( geometry.index !== null ) {

            attributes.remove( geometry.index );

        }

        for ( const name in geometry.attributes ) {

            attributes.remove( geometry.attributes[ name ] );

        }

        geometry.removeEventListener( 'dispose', onGeometryDispose );

        delete geometries[ geometry.id ];

        const attribute = wireframeAttributes.get( geometry );

        if ( attribute ) {

            attributes.remove( attribute );
            wireframeAttributes.delete( geometry );

        }

        bindingStates.releaseStatesOfGeometry( geometry );

        if ( geometry.isInstancedBufferGeometry === true ) {

            delete geometry._maxInstanceCount;

        }

        //

        info.memory.geometries --;

    }

    function get( object, geometry ) {

        if ( geometries[ geometry.id ] === true ) return geometry;

        geometry.addEventListener( 'dispose', onGeometryDispose );

        geometries[ geometry.id ] = true;

        info.memory.geometries ++;

        return geometry;

    }

    function update( geometry ) {

        const geometryAttributes = geometry.attributes;

        // Updating index buffer in VAO now. See WebGLBindingStates.

        for ( const name in geometryAttributes ) {

            attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );

        }

    }

    function updateWireframeAttribute( geometry ) {

        const indices = [];

        const geometryIndex = geometry.index;
        const geometryPosition = geometry.attributes.position;
        let version = 0;

        if ( geometryIndex !== null ) {

            const array = geometryIndex.array;
            version = geometryIndex.version;

            for ( let i = 0, l = array.length; i < l; i += 3 ) {

                const a = array[ i + 0 ];
                const b = array[ i + 1 ];
                const c = array[ i + 2 ];

                indices.push( a, b, b, c, c, a );

            }

        } else if ( geometryPosition !== undefined ) {

            const array = geometryPosition.array;
            version = geometryPosition.version;

            for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {

                const a = i + 0;
                const b = i + 1;
                const c = i + 2;

                indices.push( a, b, b, c, c, a );

            }

        } else {

            return;

        }

        const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
        attribute.version = version;

        // Updating index buffer in VAO now. See WebGLBindingStates

        //

        const previousAttribute = wireframeAttributes.get( geometry );

        if ( previousAttribute ) attributes.remove( previousAttribute );

        //

        wireframeAttributes.set( geometry, attribute );

    }

    function getWireframeAttribute( geometry ) {

        const currentAttribute = wireframeAttributes.get( geometry );

        if ( currentAttribute ) {

            const geometryIndex = geometry.index;

            if ( geometryIndex !== null ) {

                // if the attribute is obsolete, create a new one

                if ( currentAttribute.version < geometryIndex.version ) {

                    updateWireframeAttribute( geometry );

                }

            }

        } else {

            updateWireframeAttribute( geometry );

        }

        return wireframeAttributes.get( geometry );

    }

    return {

        get: get,
        update: update,

        getWireframeAttribute: getWireframeAttribute

    };

}

onGeometryDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • attributes.remove
  • geometry.removeEventListener
  • wireframeAttributes.get
  • wireframeAttributes.delete
  • bindingStates.releaseStatesOfGeometry

Internal Comments:

// (x5)

Code
function onGeometryDispose( event ) {

        const geometry = event.target;

        if ( geometry.index !== null ) {

            attributes.remove( geometry.index );

        }

        for ( const name in geometry.attributes ) {

            attributes.remove( geometry.attributes[ name ] );

        }

        geometry.removeEventListener( 'dispose', onGeometryDispose );

        delete geometries[ geometry.id ];

        const attribute = wireframeAttributes.get( geometry );

        if ( attribute ) {

            attributes.remove( attribute );
            wireframeAttributes.delete( geometry );

        }

        bindingStates.releaseStatesOfGeometry( geometry );

        if ( geometry.isInstancedBufferGeometry === true ) {

            delete geometry._maxInstanceCount;

        }

        //

        info.memory.geometries --;

    }

get(object: any, geometry: any): any

Parameters:

  • object any
  • geometry any

Returns: any

Calls:

  • geometry.addEventListener
Code
function get( object, geometry ) {

        if ( geometries[ geometry.id ] === true ) return geometry;

        geometry.addEventListener( 'dispose', onGeometryDispose );

        geometries[ geometry.id ] = true;

        info.memory.geometries ++;

        return geometry;

    }

update(geometry: any): void

Parameters:

  • geometry any

Returns: void

Calls:

  • attributes.update

Internal Comments:

// Updating index buffer in VAO now. See WebGLBindingStates.

Code
function update( geometry ) {

        const geometryAttributes = geometry.attributes;

        // Updating index buffer in VAO now. See WebGLBindingStates.

        for ( const name in geometryAttributes ) {

            attributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );

        }

    }

updateWireframeAttribute(geometry: any): void

Parameters:

  • geometry any

Returns: void

Calls:

  • indices.push
  • arrayNeedsUint32 (from ./three.core.js)
  • wireframeAttributes.get
  • attributes.remove
  • wireframeAttributes.set

Internal Comments:

// Updating index buffer in VAO now. See WebGLBindingStates (x2)
// (x6)

Code
function updateWireframeAttribute( geometry ) {

        const indices = [];

        const geometryIndex = geometry.index;
        const geometryPosition = geometry.attributes.position;
        let version = 0;

        if ( geometryIndex !== null ) {

            const array = geometryIndex.array;
            version = geometryIndex.version;

            for ( let i = 0, l = array.length; i < l; i += 3 ) {

                const a = array[ i + 0 ];
                const b = array[ i + 1 ];
                const c = array[ i + 2 ];

                indices.push( a, b, b, c, c, a );

            }

        } else if ( geometryPosition !== undefined ) {

            const array = geometryPosition.array;
            version = geometryPosition.version;

            for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {

                const a = i + 0;
                const b = i + 1;
                const c = i + 2;

                indices.push( a, b, b, c, c, a );

            }

        } else {

            return;

        }

        const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
        attribute.version = version;

        // Updating index buffer in VAO now. See WebGLBindingStates

        //

        const previousAttribute = wireframeAttributes.get( geometry );

        if ( previousAttribute ) attributes.remove( previousAttribute );

        //

        wireframeAttributes.set( geometry, attribute );

    }

getWireframeAttribute(geometry: any): any

Parameters:

  • geometry any

Returns: any

Calls:

  • wireframeAttributes.get
  • updateWireframeAttribute

Internal Comments:

// if the attribute is obsolete, create a new one

Code
function getWireframeAttribute( geometry ) {

        const currentAttribute = wireframeAttributes.get( geometry );

        if ( currentAttribute ) {

            const geometryIndex = geometry.index;

            if ( geometryIndex !== null ) {

                // if the attribute is obsolete, create a new one

                if ( currentAttribute.version < geometryIndex.version ) {

                    updateWireframeAttribute( geometry );

                }

            }

        } else {

            updateWireframeAttribute( geometry );

        }

        return wireframeAttributes.get( geometry );

    }

WebGLIndexedBufferRenderer(gl: any, extensions: any, info: any): void

Parameters:

  • gl any
  • extensions any
  • info any

Returns: void

Calls:

  • gl.drawElements
  • info.update
  • gl.drawElementsInstanced
  • extensions.get
  • extension.multiDrawElementsWEBGL
  • renderInstances
  • extension.multiDrawElementsInstancedWEBGL

Internal Comments:

// (x4)

Code
function WebGLIndexedBufferRenderer( gl, extensions, info ) {

    let mode;

    function setMode( value ) {

        mode = value;

    }

    let type, bytesPerElement;

    function setIndex( value ) {

        type = value.type;
        bytesPerElement = value.bytesPerElement;

    }

    function render( start, count ) {

        gl.drawElements( mode, count, type, start * bytesPerElement );

        info.update( count, mode, 1 );

    }

    function renderInstances( start, count, primcount ) {

        if ( primcount === 0 ) return;

        gl.drawElementsInstanced( 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' );
        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 );


    }

    function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );

        if ( extension === null ) {

            for ( let i = 0; i < starts.length; i ++ ) {

                renderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );

            }

        } else {

            extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );

            let elementCount = 0;
            for ( let i = 0; i < drawCount; i ++ ) {

                elementCount += counts[ i ] * primcount[ i ];

            }

            info.update( elementCount, mode, 1 );

        }

    }

    //

    this.setMode = setMode;
    this.setIndex = setIndex;
    this.render = render;
    this.renderInstances = renderInstances;
    this.renderMultiDraw = renderMultiDraw;
    this.renderMultiDrawInstances = renderMultiDrawInstances;

}

setMode(value: any): void

Parameters:

  • value any

Returns: void

Code
function setMode( value ) {

        mode = value;

    }

setIndex(value: any): void

Parameters:

  • value any

Returns: void

Code
function setIndex( value ) {

        type = value.type;
        bytesPerElement = value.bytesPerElement;

    }

render(start: any, count: any): void

Parameters:

  • start any
  • count any

Returns: void

Calls:

  • gl.drawElements
  • info.update
Code
function render( start, count ) {

        gl.drawElements( mode, count, type, start * bytesPerElement );

        info.update( count, mode, 1 );

    }

renderInstances(start: any, count: any, primcount: any): void

Parameters:

  • start any
  • count any
  • primcount any

Returns: void

Calls:

  • gl.drawElementsInstanced
  • info.update
Code
function renderInstances( start, count, primcount ) {

        if ( primcount === 0 ) return;

        gl.drawElementsInstanced( mode, count, type, start * bytesPerElement, primcount );

        info.update( count, mode, primcount );

    }

renderMultiDraw(starts: any, counts: any, drawCount: any): void

Parameters:

  • starts any
  • counts any
  • drawCount any

Returns: void

Calls:

  • extensions.get
  • extension.multiDrawElementsWEBGL
  • info.update
Code
function renderMultiDraw( starts, counts, drawCount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );
        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 );


    }

renderMultiDrawInstances(starts: any, counts: any, drawCount: any, primcount: any): void

Parameters:

  • starts any
  • counts any
  • drawCount any
  • primcount any

Returns: void

Calls:

  • extensions.get
  • renderInstances
  • extension.multiDrawElementsInstancedWEBGL
  • info.update
Code
function renderMultiDrawInstances( starts, counts, drawCount, primcount ) {

        if ( drawCount === 0 ) return;

        const extension = extensions.get( 'WEBGL_multi_draw' );

        if ( extension === null ) {

            for ( let i = 0; i < starts.length; i ++ ) {

                renderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );

            }

        } else {

            extension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );

            let elementCount = 0;
            for ( let i = 0; i < drawCount; i ++ ) {

                elementCount += counts[ i ] * primcount[ i ];

            }

            info.update( elementCount, mode, 1 );

        }

    }

WebGLInfo(gl: any): { memory: { geometries: number; textures: number; }; render: { frame: number; calls: number; triangles: number; points: number; lines: number; }; programs: any; autoReset: boolean; reset: () => void; update: (count: any, mode: any, instanceCount: any) => void; }

Parameters:

  • gl any

Returns: { memory: { geometries: number; textures: number; }; render: { frame: number; calls: number; triangles: number; points: number; lines: number; }; programs: any; autoReset: boolean; reset: () => void; update: (count: any, mode: any, instanceCount: any) => void; }

Calls:

  • console.error
Code
function WebGLInfo( gl ) {

    const memory = {
        geometries: 0,
        textures: 0
    };

    const render = {
        frame: 0,
        calls: 0,
        triangles: 0,
        points: 0,
        lines: 0
    };

    function update( count, mode, instanceCount ) {

        render.calls ++;

        switch ( mode ) {

            case gl.TRIANGLES:
                render.triangles += instanceCount * ( count / 3 );
                break;

            case gl.LINES:
                render.lines += instanceCount * ( count / 2 );
                break;

            case gl.LINE_STRIP:
                render.lines += instanceCount * ( count - 1 );
                break;

            case gl.LINE_LOOP:
                render.lines += instanceCount * count;
                break;

            case gl.POINTS:
                render.points += instanceCount * count;
                break;

            default:
                console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
                break;

        }

    }

    function reset() {

        render.calls = 0;
        render.triangles = 0;
        render.points = 0;
        render.lines = 0;

    }

    return {
        memory: memory,
        render: render,
        programs: null,
        autoReset: true,
        reset: reset,
        update: update
    };

}

update(count: any, mode: any, instanceCount: any): void

Parameters:

  • count any
  • mode any
  • instanceCount any

Returns: void

Calls:

  • console.error
Code
function update( count, mode, instanceCount ) {

        render.calls ++;

        switch ( mode ) {

            case gl.TRIANGLES:
                render.triangles += instanceCount * ( count / 3 );
                break;

            case gl.LINES:
                render.lines += instanceCount * ( count / 2 );
                break;

            case gl.LINE_STRIP:
                render.lines += instanceCount * ( count - 1 );
                break;

            case gl.LINE_LOOP:
                render.lines += instanceCount * count;
                break;

            case gl.POINTS:
                render.points += instanceCount * count;
                break;

            default:
                console.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );
                break;

        }

    }

reset(): void

Returns: void

Code
function reset() {

        render.calls = 0;
        render.triangles = 0;
        render.points = 0;
        render.lines = 0;

    }

WebGLMorphtargets(gl: any, capabilities: any, textures: any): { update: (object: any, geometry: any, program: any) => void; }

Parameters:

  • gl any
  • capabilities any
  • textures any

Returns: { update: (object: any, geometry: any, program: any) => void; }

Calls:

  • morphTextures.get
  • entry.texture.dispose
  • Math.ceil
  • morph.fromBufferAttribute
  • morphTextures.set
  • texture.dispose
  • morphTextures.delete
  • geometry.removeEventListener
  • geometry.addEventListener
  • program.getUniforms().setValue

Internal Comments:

// the following encodes morph targets into an array of data textures. Each layer represents a single morph target. (x2)
// fill buffer (x2)
//

Code
function WebGLMorphtargets( gl, capabilities, textures ) {

    const morphTextures = new WeakMap();
    const morph = new Vector4();

    function update( object, geometry, program ) {

        const objectInfluences = object.morphTargetInfluences;

        // the following encodes morph targets into an array of data textures. Each layer represents a single morph target.

        const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
        const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

        let entry = morphTextures.get( geometry );

        if ( entry === undefined || entry.count !== morphTargetsCount ) {

            if ( entry !== undefined ) entry.texture.dispose();

            const hasMorphPosition = geometry.morphAttributes.position !== undefined;
            const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
            const hasMorphColors = geometry.morphAttributes.color !== undefined;

            const morphTargets = geometry.morphAttributes.position || [];
            const morphNormals = geometry.morphAttributes.normal || [];
            const morphColors = geometry.morphAttributes.color || [];

            let vertexDataCount = 0;

            if ( hasMorphPosition === true ) vertexDataCount = 1;
            if ( hasMorphNormals === true ) vertexDataCount = 2;
            if ( hasMorphColors === true ) vertexDataCount = 3;

            let width = geometry.attributes.position.count * vertexDataCount;
            let height = 1;

            if ( width > capabilities.maxTextureSize ) {

                height = Math.ceil( width / capabilities.maxTextureSize );
                width = capabilities.maxTextureSize;

            }

            const buffer = new Float32Array( width * height * 4 * morphTargetsCount );

            const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
            texture.type = FloatType;
            texture.needsUpdate = true;

            // fill buffer

            const vertexDataStride = vertexDataCount * 4;

            for ( let i = 0; i < morphTargetsCount; i ++ ) {

                const morphTarget = morphTargets[ i ];
                const morphNormal = morphNormals[ i ];
                const morphColor = morphColors[ i ];

                const offset = width * height * 4 * i;

                for ( let j = 0; j < morphTarget.count; j ++ ) {

                    const stride = j * vertexDataStride;

                    if ( hasMorphPosition === true ) {

                        morph.fromBufferAttribute( morphTarget, j );

                        buffer[ offset + stride + 0 ] = morph.x;
                        buffer[ offset + stride + 1 ] = morph.y;
                        buffer[ offset + stride + 2 ] = morph.z;
                        buffer[ offset + stride + 3 ] = 0;

                    }

                    if ( hasMorphNormals === true ) {

                        morph.fromBufferAttribute( morphNormal, j );

                        buffer[ offset + stride + 4 ] = morph.x;
                        buffer[ offset + stride + 5 ] = morph.y;
                        buffer[ offset + stride + 6 ] = morph.z;
                        buffer[ offset + stride + 7 ] = 0;

                    }

                    if ( hasMorphColors === true ) {

                        morph.fromBufferAttribute( morphColor, j );

                        buffer[ offset + stride + 8 ] = morph.x;
                        buffer[ offset + stride + 9 ] = morph.y;
                        buffer[ offset + stride + 10 ] = morph.z;
                        buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;

                    }

                }

            }

            entry = {
                count: morphTargetsCount,
                texture: texture,
                size: new Vector2( width, height )
            };

            morphTextures.set( geometry, entry );

            function disposeTexture() {

                texture.dispose();

                morphTextures.delete( geometry );

                geometry.removeEventListener( 'dispose', disposeTexture );

            }

            geometry.addEventListener( 'dispose', disposeTexture );

        }

        //
        if ( object.isInstancedMesh === true && object.morphTexture !== null ) {

            program.getUniforms().setValue( gl, 'morphTexture', object.morphTexture, textures );

        } else {

            let morphInfluencesSum = 0;

            for ( let i = 0; i < objectInfluences.length; i ++ ) {

                morphInfluencesSum += objectInfluences[ i ];

            }

            const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;


            program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
            program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );

        }

        program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
        program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );

    }

    return {

        update: update

    };

}

update(object: any, geometry: any, program: any): void

Parameters:

  • object any
  • geometry any
  • program any

Returns: void

Calls:

  • morphTextures.get
  • entry.texture.dispose
  • Math.ceil
  • morph.fromBufferAttribute
  • morphTextures.set
  • texture.dispose
  • morphTextures.delete
  • geometry.removeEventListener
  • geometry.addEventListener
  • program.getUniforms().setValue

Internal Comments:

// the following encodes morph targets into an array of data textures. Each layer represents a single morph target. (x2)
// fill buffer (x2)
//

Code
function update( object, geometry, program ) {

        const objectInfluences = object.morphTargetInfluences;

        // the following encodes morph targets into an array of data textures. Each layer represents a single morph target.

        const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
        const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

        let entry = morphTextures.get( geometry );

        if ( entry === undefined || entry.count !== morphTargetsCount ) {

            if ( entry !== undefined ) entry.texture.dispose();

            const hasMorphPosition = geometry.morphAttributes.position !== undefined;
            const hasMorphNormals = geometry.morphAttributes.normal !== undefined;
            const hasMorphColors = geometry.morphAttributes.color !== undefined;

            const morphTargets = geometry.morphAttributes.position || [];
            const morphNormals = geometry.morphAttributes.normal || [];
            const morphColors = geometry.morphAttributes.color || [];

            let vertexDataCount = 0;

            if ( hasMorphPosition === true ) vertexDataCount = 1;
            if ( hasMorphNormals === true ) vertexDataCount = 2;
            if ( hasMorphColors === true ) vertexDataCount = 3;

            let width = geometry.attributes.position.count * vertexDataCount;
            let height = 1;

            if ( width > capabilities.maxTextureSize ) {

                height = Math.ceil( width / capabilities.maxTextureSize );
                width = capabilities.maxTextureSize;

            }

            const buffer = new Float32Array( width * height * 4 * morphTargetsCount );

            const texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );
            texture.type = FloatType;
            texture.needsUpdate = true;

            // fill buffer

            const vertexDataStride = vertexDataCount * 4;

            for ( let i = 0; i < morphTargetsCount; i ++ ) {

                const morphTarget = morphTargets[ i ];
                const morphNormal = morphNormals[ i ];
                const morphColor = morphColors[ i ];

                const offset = width * height * 4 * i;

                for ( let j = 0; j < morphTarget.count; j ++ ) {

                    const stride = j * vertexDataStride;

                    if ( hasMorphPosition === true ) {

                        morph.fromBufferAttribute( morphTarget, j );

                        buffer[ offset + stride + 0 ] = morph.x;
                        buffer[ offset + stride + 1 ] = morph.y;
                        buffer[ offset + stride + 2 ] = morph.z;
                        buffer[ offset + stride + 3 ] = 0;

                    }

                    if ( hasMorphNormals === true ) {

                        morph.fromBufferAttribute( morphNormal, j );

                        buffer[ offset + stride + 4 ] = morph.x;
                        buffer[ offset + stride + 5 ] = morph.y;
                        buffer[ offset + stride + 6 ] = morph.z;
                        buffer[ offset + stride + 7 ] = 0;

                    }

                    if ( hasMorphColors === true ) {

                        morph.fromBufferAttribute( morphColor, j );

                        buffer[ offset + stride + 8 ] = morph.x;
                        buffer[ offset + stride + 9 ] = morph.y;
                        buffer[ offset + stride + 10 ] = morph.z;
                        buffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;

                    }

                }

            }

            entry = {
                count: morphTargetsCount,
                texture: texture,
                size: new Vector2( width, height )
            };

            morphTextures.set( geometry, entry );

            function disposeTexture() {

                texture.dispose();

                morphTextures.delete( geometry );

                geometry.removeEventListener( 'dispose', disposeTexture );

            }

            geometry.addEventListener( 'dispose', disposeTexture );

        }

        //
        if ( object.isInstancedMesh === true && object.morphTexture !== null ) {

            program.getUniforms().setValue( gl, 'morphTexture', object.morphTexture, textures );

        } else {

            let morphInfluencesSum = 0;

            for ( let i = 0; i < objectInfluences.length; i ++ ) {

                morphInfluencesSum += objectInfluences[ i ];

            }

            const morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;


            program.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );
            program.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );

        }

        program.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );
        program.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );

    }

disposeTexture(): void

Returns: void

Calls:

  • texture.dispose
  • morphTextures.delete
  • geometry.removeEventListener
Code
function disposeTexture() {

                texture.dispose();

                morphTextures.delete( geometry );

                geometry.removeEventListener( 'dispose', disposeTexture );

            }

WebGLObjects(gl: any, geometries: any, attributes: any, info: any): { update: (object: any) => any; dispose: () => void; }

Parameters:

  • gl any
  • geometries any
  • attributes any
  • info any

Returns: { update: (object: any) => any; dispose: () => void; }

Calls:

  • geometries.get
  • updateMap.get
  • geometries.update
  • updateMap.set
  • object.hasEventListener
  • object.addEventListener
  • attributes.update
  • skeleton.update
  • instancedMesh.removeEventListener
  • attributes.remove

Internal Comments:

// Update once per frame

Code
function WebGLObjects( gl, geometries, attributes, info ) {

    let updateMap = new WeakMap();

    function update( object ) {

        const frame = info.render.frame;

        const geometry = object.geometry;
        const buffergeometry = geometries.get( object, geometry );

        // Update once per frame

        if ( updateMap.get( buffergeometry ) !== frame ) {

            geometries.update( buffergeometry );

            updateMap.set( buffergeometry, frame );

        }

        if ( object.isInstancedMesh ) {

            if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {

                object.addEventListener( 'dispose', onInstancedMeshDispose );

            }

            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 ) {

                skeleton.update();

                updateMap.set( skeleton, frame );

            }

        }

        return buffergeometry;

    }

    function dispose() {

        updateMap = new WeakMap();

    }

    function onInstancedMeshDispose( event ) {

        const instancedMesh = event.target;

        instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );

        attributes.remove( instancedMesh.instanceMatrix );

        if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );

    }

    return {

        update: update,
        dispose: dispose

    };

}

update(object: any): any

Parameters:

  • object any

Returns: any

Calls:

  • geometries.get
  • updateMap.get
  • geometries.update
  • updateMap.set
  • object.hasEventListener
  • object.addEventListener
  • attributes.update
  • skeleton.update

Internal Comments:

// Update once per frame

Code
function update( object ) {

        const frame = info.render.frame;

        const geometry = object.geometry;
        const buffergeometry = geometries.get( object, geometry );

        // Update once per frame

        if ( updateMap.get( buffergeometry ) !== frame ) {

            geometries.update( buffergeometry );

            updateMap.set( buffergeometry, frame );

        }

        if ( object.isInstancedMesh ) {

            if ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {

                object.addEventListener( 'dispose', onInstancedMeshDispose );

            }

            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 ) {

                skeleton.update();

                updateMap.set( skeleton, frame );

            }

        }

        return buffergeometry;

    }

dispose(): void

Returns: void

Code
function dispose() {

        updateMap = new WeakMap();

    }

onInstancedMeshDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • instancedMesh.removeEventListener
  • attributes.remove
Code
function onInstancedMeshDispose( event ) {

        const instancedMesh = event.target;

        instancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );

        attributes.remove( instancedMesh.instanceMatrix );

        if ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );

    }

flatten(array: any, nBlocks: any, blockSize: any): any

Parameters:

  • array any
  • nBlocks any
  • blockSize any

Returns: any

Calls:

  • firstElem.toArray
  • array[ i ].toArray

Internal Comments:

// unoptimized: ! isNaN( firstElem ) (x2)
// see http://jacksondunstan.com/articles/983 (x2)

Code
function flatten( array, nBlocks, blockSize ) {

    const firstElem = array[ 0 ];

    if ( firstElem <= 0 || firstElem > 0 ) return array;
    // unoptimized: ! isNaN( firstElem )
    // see http://jacksondunstan.com/articles/983

    const n = nBlocks * blockSize;
    let r = arrayCacheF32[ n ];

    if ( r === undefined ) {

        r = new Float32Array( n );
        arrayCacheF32[ n ] = r;

    }

    if ( nBlocks !== 0 ) {

        firstElem.toArray( r, 0 );

        for ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {

            offset += blockSize;
            array[ i ].toArray( r, offset );

        }

    }

    return r;

}

arraysEqual(a: any, b: any): boolean

Parameters:

  • a any
  • b any

Returns: boolean

Code
function arraysEqual( a, b ) {

    if ( a.length !== b.length ) return false;

    for ( let i = 0, l = a.length; i < l; i ++ ) {

        if ( a[ i ] !== b[ i ] ) return false;

    }

    return true;

}

copyArray(a: any, b: any): void

Parameters:

  • a any
  • b any

Returns: void

Code
function copyArray( a, b ) {

    for ( let i = 0, l = b.length; i < l; i ++ ) {

        a[ i ] = b[ i ];

    }

}

allocTexUnits(textures: any, n: any): any

Parameters:

  • textures any
  • n any

Returns: any

Calls:

  • textures.allocateTextureUnit
Code
function allocTexUnits( textures, n ) {

    let r = arrayCacheI32[ n ];

    if ( r === undefined ) {

        r = new Int32Array( n );
        arrayCacheI32[ n ] = r;

    }

    for ( let i = 0; i !== n; ++ i ) {

        r[ i ] = textures.allocateTextureUnit();

    }

    return r;

}

setValueV1f(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1f
Code
function setValueV1f( gl, v ) {

    const cache = this.cache;

    if ( cache[ 0 ] === v ) return;

    gl.uniform1f( this.addr, v );

    cache[ 0 ] = v;

}

setValueV2f(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform2f
  • arraysEqual
  • gl.uniform2fv
  • copyArray
Code
function setValueV2f( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {

            gl.uniform2f( this.addr, v.x, v.y );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform2fv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV3f(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform3f
  • arraysEqual
  • gl.uniform3fv
  • copyArray
Code
function setValueV3f( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {

            gl.uniform3f( this.addr, v.x, v.y, v.z );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;

        }

    } else if ( v.r !== undefined ) {

        if ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {

            gl.uniform3f( this.addr, v.r, v.g, v.b );

            cache[ 0 ] = v.r;
            cache[ 1 ] = v.g;
            cache[ 2 ] = v.b;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform3fv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV4f(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform4f
  • arraysEqual
  • gl.uniform4fv
  • copyArray
Code
function setValueV4f( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {

            gl.uniform4f( this.addr, v.x, v.y, v.z, v.w );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;
            cache[ 3 ] = v.w;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform4fv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueM2(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • arraysEqual
  • gl.uniformMatrix2fv
  • copyArray
  • mat2array.set
Code
function setValueM2( gl, v ) {

    const cache = this.cache;
    const elements = v.elements;

    if ( elements === undefined ) {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniformMatrix2fv( this.addr, false, v );

        copyArray( cache, v );

    } else {

        if ( arraysEqual( cache, elements ) ) return;

        mat2array.set( elements );

        gl.uniformMatrix2fv( this.addr, false, mat2array );

        copyArray( cache, elements );

    }

}

setValueM3(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • arraysEqual
  • gl.uniformMatrix3fv
  • copyArray
  • mat3array.set
Code
function setValueM3( gl, v ) {

    const cache = this.cache;
    const elements = v.elements;

    if ( elements === undefined ) {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniformMatrix3fv( this.addr, false, v );

        copyArray( cache, v );

    } else {

        if ( arraysEqual( cache, elements ) ) return;

        mat3array.set( elements );

        gl.uniformMatrix3fv( this.addr, false, mat3array );

        copyArray( cache, elements );

    }

}

setValueM4(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • arraysEqual
  • gl.uniformMatrix4fv
  • copyArray
  • mat4array.set
Code
function setValueM4( gl, v ) {

    const cache = this.cache;
    const elements = v.elements;

    if ( elements === undefined ) {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniformMatrix4fv( this.addr, false, v );

        copyArray( cache, v );

    } else {

        if ( arraysEqual( cache, elements ) ) return;

        mat4array.set( elements );

        gl.uniformMatrix4fv( this.addr, false, mat4array );

        copyArray( cache, elements );

    }

}

setValueV1i(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1i
Code
function setValueV1i( gl, v ) {

    const cache = this.cache;

    if ( cache[ 0 ] === v ) return;

    gl.uniform1i( this.addr, v );

    cache[ 0 ] = v;

}

setValueV2i(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform2i
  • arraysEqual
  • gl.uniform2iv
  • copyArray
Code
function setValueV2i( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {

            gl.uniform2i( this.addr, v.x, v.y );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform2iv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV3i(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform3i
  • arraysEqual
  • gl.uniform3iv
  • copyArray
Code
function setValueV3i( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {

            gl.uniform3i( this.addr, v.x, v.y, v.z );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform3iv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV4i(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform4i
  • arraysEqual
  • gl.uniform4iv
  • copyArray
Code
function setValueV4i( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {

            gl.uniform4i( this.addr, v.x, v.y, v.z, v.w );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;
            cache[ 3 ] = v.w;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform4iv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV1ui(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1ui
Code
function setValueV1ui( gl, v ) {

    const cache = this.cache;

    if ( cache[ 0 ] === v ) return;

    gl.uniform1ui( this.addr, v );

    cache[ 0 ] = v;

}

setValueV2ui(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform2ui
  • arraysEqual
  • gl.uniform2uiv
  • copyArray
Code
function setValueV2ui( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {

            gl.uniform2ui( this.addr, v.x, v.y );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform2uiv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV3ui(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform3ui
  • arraysEqual
  • gl.uniform3uiv
  • copyArray
Code
function setValueV3ui( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {

            gl.uniform3ui( this.addr, v.x, v.y, v.z );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform3uiv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueV4ui(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform4ui
  • arraysEqual
  • gl.uniform4uiv
  • copyArray
Code
function setValueV4ui( gl, v ) {

    const cache = this.cache;

    if ( v.x !== undefined ) {

        if ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {

            gl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );

            cache[ 0 ] = v.x;
            cache[ 1 ] = v.y;
            cache[ 2 ] = v.z;
            cache[ 3 ] = v.w;

        }

    } else {

        if ( arraysEqual( cache, v ) ) return;

        gl.uniform4uiv( this.addr, v );

        copyArray( cache, v );

    }

}

setValueT1(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • textures.allocateTextureUnit
  • gl.uniform1i
  • textures.setTexture2D
Code
function setValueT1( gl, v, textures ) {

    const cache = this.cache;
    const unit = textures.allocateTextureUnit();

    if ( cache[ 0 ] !== unit ) {

        gl.uniform1i( this.addr, unit );
        cache[ 0 ] = unit;

    }

    let emptyTexture2D;

    if ( this.type === gl.SAMPLER_2D_SHADOW ) {

        emptyShadowTexture.compareFunction = LessEqualCompare; // #28670
        emptyTexture2D = emptyShadowTexture;

    } else {

        emptyTexture2D = emptyTexture;

    }

    textures.setTexture2D( v || emptyTexture2D, unit );

}

setValueT3D1(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • textures.allocateTextureUnit
  • gl.uniform1i
  • textures.setTexture3D
Code
function setValueT3D1( gl, v, textures ) {

    const cache = this.cache;
    const unit = textures.allocateTextureUnit();

    if ( cache[ 0 ] !== unit ) {

        gl.uniform1i( this.addr, unit );
        cache[ 0 ] = unit;

    }

    textures.setTexture3D( v || empty3dTexture, unit );

}

setValueT6(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • textures.allocateTextureUnit
  • gl.uniform1i
  • textures.setTextureCube
Code
function setValueT6( gl, v, textures ) {

    const cache = this.cache;
    const unit = textures.allocateTextureUnit();

    if ( cache[ 0 ] !== unit ) {

        gl.uniform1i( this.addr, unit );
        cache[ 0 ] = unit;

    }

    textures.setTextureCube( v || emptyCubeTexture, unit );

}

setValueT2DArray1(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • textures.allocateTextureUnit
  • gl.uniform1i
  • textures.setTexture2DArray
Code
function setValueT2DArray1( gl, v, textures ) {

    const cache = this.cache;
    const unit = textures.allocateTextureUnit();

    if ( cache[ 0 ] !== unit ) {

        gl.uniform1i( this.addr, unit );
        cache[ 0 ] = unit;

    }

    textures.setTexture2DArray( v || emptyArrayTexture, unit );

}

getSingularSetter(type: any): (gl: any, v: any, textures: any) => void

Parameters:

  • type any

Returns: (gl: any, v: any, textures: any) => void

Code
function getSingularSetter( type ) {

    switch ( type ) {

        case 0x1406: return setValueV1f; // FLOAT
        case 0x8b50: return setValueV2f; // _VEC2
        case 0x8b51: return setValueV3f; // _VEC3
        case 0x8b52: return setValueV4f; // _VEC4

        case 0x8b5a: return setValueM2; // _MAT2
        case 0x8b5b: return setValueM3; // _MAT3
        case 0x8b5c: return setValueM4; // _MAT4

        case 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL
        case 0x8b53: case 0x8b57: return setValueV2i; // _VEC2
        case 0x8b54: case 0x8b58: return setValueV3i; // _VEC3
        case 0x8b55: case 0x8b59: return setValueV4i; // _VEC4

        case 0x1405: return setValueV1ui; // UINT
        case 0x8dc6: return setValueV2ui; // _VEC2
        case 0x8dc7: return setValueV3ui; // _VEC3
        case 0x8dc8: return setValueV4ui; // _VEC4

        case 0x8b5e: // SAMPLER_2D
        case 0x8d66: // SAMPLER_EXTERNAL_OES
        case 0x8dca: // INT_SAMPLER_2D
        case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
        case 0x8b62: // SAMPLER_2D_SHADOW
            return setValueT1;

        case 0x8b5f: // SAMPLER_3D
        case 0x8dcb: // INT_SAMPLER_3D
        case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
            return setValueT3D1;

        case 0x8b60: // SAMPLER_CUBE
        case 0x8dcc: // INT_SAMPLER_CUBE
        case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
        case 0x8dc5: // SAMPLER_CUBE_SHADOW
            return setValueT6;

        case 0x8dc1: // SAMPLER_2D_ARRAY
        case 0x8dcf: // INT_SAMPLER_2D_ARRAY
        case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
        case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
            return setValueT2DArray1;

    }

}

setValueV1fArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1fv
Code
function setValueV1fArray( gl, v ) {

    gl.uniform1fv( this.addr, v );

}

setValueV2fArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniform2fv
Code
function setValueV2fArray( gl, v ) {

    const data = flatten( v, this.size, 2 );

    gl.uniform2fv( this.addr, data );

}

setValueV3fArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniform3fv
Code
function setValueV3fArray( gl, v ) {

    const data = flatten( v, this.size, 3 );

    gl.uniform3fv( this.addr, data );

}

setValueV4fArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniform4fv
Code
function setValueV4fArray( gl, v ) {

    const data = flatten( v, this.size, 4 );

    gl.uniform4fv( this.addr, data );

}

setValueM2Array(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniformMatrix2fv
Code
function setValueM2Array( gl, v ) {

    const data = flatten( v, this.size, 4 );

    gl.uniformMatrix2fv( this.addr, false, data );

}

setValueM3Array(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniformMatrix3fv
Code
function setValueM3Array( gl, v ) {

    const data = flatten( v, this.size, 9 );

    gl.uniformMatrix3fv( this.addr, false, data );

}

setValueM4Array(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • flatten
  • gl.uniformMatrix4fv
Code
function setValueM4Array( gl, v ) {

    const data = flatten( v, this.size, 16 );

    gl.uniformMatrix4fv( this.addr, false, data );

}

setValueV1iArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1iv
Code
function setValueV1iArray( gl, v ) {

    gl.uniform1iv( this.addr, v );

}

setValueV2iArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform2iv
Code
function setValueV2iArray( gl, v ) {

    gl.uniform2iv( this.addr, v );

}

setValueV3iArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform3iv
Code
function setValueV3iArray( gl, v ) {

    gl.uniform3iv( this.addr, v );

}

setValueV4iArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform4iv
Code
function setValueV4iArray( gl, v ) {

    gl.uniform4iv( this.addr, v );

}

setValueV1uiArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform1uiv
Code
function setValueV1uiArray( gl, v ) {

    gl.uniform1uiv( this.addr, v );

}

setValueV2uiArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform2uiv
Code
function setValueV2uiArray( gl, v ) {

    gl.uniform2uiv( this.addr, v );

}

setValueV3uiArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform3uiv
Code
function setValueV3uiArray( gl, v ) {

    gl.uniform3uiv( this.addr, v );

}

setValueV4uiArray(gl: any, v: any): void

Parameters:

  • gl any
  • v any

Returns: void

Calls:

  • gl.uniform4uiv
Code
function setValueV4uiArray( gl, v ) {

    gl.uniform4uiv( this.addr, v );

}

setValueT1Array(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • allocTexUnits
  • arraysEqual
  • gl.uniform1iv
  • copyArray
  • textures.setTexture2D
Code
function setValueT1Array( gl, v, textures ) {

    const cache = this.cache;

    const n = v.length;

    const units = allocTexUnits( textures, n );

    if ( ! arraysEqual( cache, units ) ) {

        gl.uniform1iv( this.addr, units );

        copyArray( cache, units );

    }

    for ( let i = 0; i !== n; ++ i ) {

        textures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );

    }

}

setValueT3DArray(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • allocTexUnits
  • arraysEqual
  • gl.uniform1iv
  • copyArray
  • textures.setTexture3D
Code
function setValueT3DArray( gl, v, textures ) {

    const cache = this.cache;

    const n = v.length;

    const units = allocTexUnits( textures, n );

    if ( ! arraysEqual( cache, units ) ) {

        gl.uniform1iv( this.addr, units );

        copyArray( cache, units );

    }

    for ( let i = 0; i !== n; ++ i ) {

        textures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );

    }

}

setValueT6Array(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • allocTexUnits
  • arraysEqual
  • gl.uniform1iv
  • copyArray
  • textures.setTextureCube
Code
function setValueT6Array( gl, v, textures ) {

    const cache = this.cache;

    const n = v.length;

    const units = allocTexUnits( textures, n );

    if ( ! arraysEqual( cache, units ) ) {

        gl.uniform1iv( this.addr, units );

        copyArray( cache, units );

    }

    for ( let i = 0; i !== n; ++ i ) {

        textures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );

    }

}

setValueT2DArrayArray(gl: any, v: any, textures: any): void

Parameters:

  • gl any
  • v any
  • textures any

Returns: void

Calls:

  • allocTexUnits
  • arraysEqual
  • gl.uniform1iv
  • copyArray
  • textures.setTexture2DArray
Code
function setValueT2DArrayArray( gl, v, textures ) {

    const cache = this.cache;

    const n = v.length;

    const units = allocTexUnits( textures, n );

    if ( ! arraysEqual( cache, units ) ) {

        gl.uniform1iv( this.addr, units );

        copyArray( cache, units );

    }

    for ( let i = 0; i !== n; ++ i ) {

        textures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );

    }

}

getPureArraySetter(type: any): (gl: any, v: any, textures: any) => void

Parameters:

  • type any

Returns: (gl: any, v: any, textures: any) => void

Code
function getPureArraySetter( type ) {

    switch ( type ) {

        case 0x1406: return setValueV1fArray; // FLOAT
        case 0x8b50: return setValueV2fArray; // _VEC2
        case 0x8b51: return setValueV3fArray; // _VEC3
        case 0x8b52: return setValueV4fArray; // _VEC4

        case 0x8b5a: return setValueM2Array; // _MAT2
        case 0x8b5b: return setValueM3Array; // _MAT3
        case 0x8b5c: return setValueM4Array; // _MAT4

        case 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL
        case 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2
        case 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3
        case 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4

        case 0x1405: return setValueV1uiArray; // UINT
        case 0x8dc6: return setValueV2uiArray; // _VEC2
        case 0x8dc7: return setValueV3uiArray; // _VEC3
        case 0x8dc8: return setValueV4uiArray; // _VEC4

        case 0x8b5e: // SAMPLER_2D
        case 0x8d66: // SAMPLER_EXTERNAL_OES
        case 0x8dca: // INT_SAMPLER_2D
        case 0x8dd2: // UNSIGNED_INT_SAMPLER_2D
        case 0x8b62: // SAMPLER_2D_SHADOW
            return setValueT1Array;

        case 0x8b5f: // SAMPLER_3D
        case 0x8dcb: // INT_SAMPLER_3D
        case 0x8dd3: // UNSIGNED_INT_SAMPLER_3D
            return setValueT3DArray;

        case 0x8b60: // SAMPLER_CUBE
        case 0x8dcc: // INT_SAMPLER_CUBE
        case 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE
        case 0x8dc5: // SAMPLER_CUBE_SHADOW
            return setValueT6Array;

        case 0x8dc1: // SAMPLER_2D_ARRAY
        case 0x8dcf: // INT_SAMPLER_2D_ARRAY
        case 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY
        case 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW
            return setValueT2DArrayArray;

    }

}

StructuredUniform.setValue(gl: any, value: any, textures: any): void

Parameters:

  • gl any
  • value any
  • textures any

Returns: void

Calls:

  • u.setValue
Code
setValue( gl, value, textures ) {

        const seq = this.seq;

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            u.setValue( gl, value[ u.id ], textures );

        }

    }

addUniform(container: any, uniformObject: any): void

Parameters:

  • container any
  • uniformObject any

Returns: void

Calls:

  • container.seq.push
Code
function addUniform( container, uniformObject ) {

    container.seq.push( uniformObject );
    container.map[ uniformObject.id ] = uniformObject;

}

parseUniform(activeInfo: any, addr: any, container: any): void

Parameters:

  • activeInfo any
  • addr any
  • container any

Returns: void

Calls:

  • RePathPart.exec
  • addUniform

Internal Comments:

// reset RegExp object, because of the early exit of a previous run (x4)
// bare name or "pure" bottom-level array "[0]" suffix (x3)
// step into inner node / create it in case it doesn't exist (x2)

Code
function parseUniform( activeInfo, addr, container ) {

    const path = activeInfo.name,
        pathLength = path.length;

    // reset RegExp object, because of the early exit of a previous run
    RePathPart.lastIndex = 0;

    while ( true ) {

        const match = RePathPart.exec( path ),
            matchEnd = RePathPart.lastIndex;

        let id = match[ 1 ];
        const idIsIndex = match[ 2 ] === ']',
            subscript = match[ 3 ];

        if ( idIsIndex ) id = id | 0; // convert to integer

        if ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {

            // bare name or "pure" bottom-level array "[0]" suffix

            addUniform( container, subscript === undefined ?
                new SingleUniform( id, activeInfo, addr ) :
                new PureArrayUniform( id, activeInfo, addr ) );

            break;

        } else {

            // step into inner node / create it in case it doesn't exist

            const map = container.map;
            let next = map[ id ];

            if ( next === undefined ) {

                next = new StructuredUniform( id );
                addUniform( container, next );

            }

            container = next;

        }

    }

}

WebGLUniforms.setValue(gl: any, name: any, value: any, textures: any): void

Parameters:

  • gl any
  • name any
  • value any
  • textures any

Returns: void

Calls:

  • u.setValue
Code
setValue( gl, name, value, textures ) {

        const u = this.map[ name ];

        if ( u !== undefined ) u.setValue( gl, value, textures );

    }

WebGLUniforms.setOptional(gl: any, object: any, name: any): void

Parameters:

  • gl any
  • object any
  • name any

Returns: void

Calls:

  • this.setValue
Code
setOptional( gl, object, name ) {

        const v = object[ name ];

        if ( v !== undefined ) this.setValue( gl, name, v );

    }

WebGLUniforms.upload(gl: any, seq: any, values: any, textures: any): void

Parameters:

  • gl any
  • seq any
  • values any
  • textures any

Returns: void

Calls:

  • u.setValue

Internal Comments:

// note: always updating when .needsUpdate is undefined (x4)

Code
static upload( gl, seq, values, textures ) {

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ],
                v = values[ u.id ];

            if ( v.needsUpdate !== false ) {

                // note: always updating when .needsUpdate is undefined
                u.setValue( gl, v.value, textures );

            }

        }

    }

WebGLUniforms.seqWithValue(seq: any, values: any): any[]

Parameters:

  • seq any
  • values any

Returns: any[]

Calls:

  • r.push
Code
static seqWithValue( seq, values ) {

        const r = [];

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            if ( u.id in values ) r.push( u );

        }

        return r;

    }

WebGLShader(gl: any, type: any, string: any): any

Parameters:

  • gl any
  • type any
  • string any

Returns: any

Calls:

  • gl.createShader
  • gl.shaderSource
  • gl.compileShader
Code
function WebGLShader( gl, type, string ) {

    const shader = gl.createShader( type );

    gl.shaderSource( shader, string );
    gl.compileShader( shader );

    return shader;

}

handleSource(string: any, errorLine: any): string

Parameters:

  • string any
  • errorLine any

Returns: string

Calls:

  • string.split
  • Math.max
  • Math.min
  • lines2.push
  • lines2.join
Code
function handleSource( string, errorLine ) {

    const lines = string.split( '\n' );
    const lines2 = [];

    const from = Math.max( errorLine - 6, 0 );
    const to = Math.min( errorLine + 6, lines.length );

    for ( let i = from; i < to; i ++ ) {

        const line = i + 1;
        lines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );

    }

    return lines2.join( '\n' );

}

getEncodingComponents(colorSpace: any): string[]

Parameters:

  • colorSpace any

Returns: string[]

Calls:

  • ColorManagement._getMatrix
  • _m0.elements.map
  • v.toFixed
  • ColorManagement.getTransfer
  • console.warn
Code
function getEncodingComponents( colorSpace ) {

    ColorManagement._getMatrix( _m0, ColorManagement.workingColorSpace, colorSpace );

    const encodingMatrix = `mat3( ${ _m0.elements.map( ( v ) => v.toFixed( 4 ) ) } )`;

    switch ( ColorManagement.getTransfer( colorSpace ) ) {

        case LinearTransfer:
            return [ encodingMatrix, 'LinearTransferOETF' ];

        case SRGBTransfer:
            return [ encodingMatrix, 'sRGBTransferOETF' ];

        default:
            console.warn( 'THREE.WebGLProgram: Unsupported color space: ', colorSpace );
            return [ encodingMatrix, 'LinearTransferOETF' ];

    }

}

getShaderErrors(gl: any, shader: any, type: any): any

Parameters:

  • gl any
  • shader any
  • type any

Returns: any

Calls:

  • gl.getShaderParameter
  • gl.getShaderInfoLog
  • shaderInfoLog.trim
  • /ERROR: 0:(\d+)/.exec
  • parseInt
  • type.toUpperCase
  • handleSource
  • gl.getShaderSource

Internal Comments:

// --enable-privileged-webgl-extension (x2)
// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) ); (x2)

Code
function getShaderErrors( gl, shader, type ) {

    const status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );

    const shaderInfoLog = gl.getShaderInfoLog( shader ) || '';
    const errors = shaderInfoLog.trim();

    if ( status && errors === '' ) return '';

    const errorMatches = /ERROR: 0:(\d+)/.exec( errors );
    if ( errorMatches ) {

        // --enable-privileged-webgl-extension
        // console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );

        const errorLine = parseInt( errorMatches[ 1 ] );
        return type.toUpperCase() + '\n\n' + errors + '\n\n' + handleSource( gl.getShaderSource( shader ), errorLine );

    } else {

        return errors;

    }

}

getTexelEncodingFunction(functionName: any, colorSpace: any): string

Parameters:

  • functionName any
  • colorSpace any

Returns: string

Calls:

  • getEncodingComponents
  • `[

    `vec4 ${functionName}( vec4 value ) {`,
    
    `   return ${components[ 1 ]}( vec4( value.rgb * ${components[ 0 ]}, value.a ) );`,
    
    '}',
    

    ].join`

Code
function getTexelEncodingFunction( functionName, colorSpace ) {

    const components = getEncodingComponents( colorSpace );

    return [

        `vec4 ${functionName}( vec4 value ) {`,

        `   return ${components[ 1 ]}( vec4( value.rgb * ${components[ 0 ]}, value.a ) );`,

        '}',

    ].join( '\n' );

}

getToneMappingFunction(functionName: any, toneMapping: any): string

Parameters:

  • functionName any
  • toneMapping any

Returns: string

Calls:

  • console.warn
Code
function getToneMappingFunction( functionName, toneMapping ) {

    let toneMappingName;

    switch ( toneMapping ) {

        case LinearToneMapping:
            toneMappingName = 'Linear';
            break;

        case ReinhardToneMapping:
            toneMappingName = 'Reinhard';
            break;

        case CineonToneMapping:
            toneMappingName = 'Cineon';
            break;

        case ACESFilmicToneMapping:
            toneMappingName = 'ACESFilmic';
            break;

        case AgXToneMapping:
            toneMappingName = 'AgX';
            break;

        case NeutralToneMapping:
            toneMappingName = 'Neutral';
            break;

        case CustomToneMapping:
            toneMappingName = 'Custom';
            break;

        default:
            console.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );
            toneMappingName = 'Linear';

    }

    return 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';

}

getLuminanceFunction(): string

Returns: string

Calls:

  • ColorManagement.getLuminanceCoefficients
  • _v0.x.toFixed
  • _v0.y.toFixed
  • _v0.z.toFixed
  • `[

    'float luminance( const in vec3 rgb ) {',
    
    `   const vec3 weights = vec3( ${ r }, ${ g }, ${ b } );`,
    
    '   return dot( weights, rgb );',
    
    '}'
    

    ].join`

Code
function getLuminanceFunction() {

    ColorManagement.getLuminanceCoefficients( _v0 );

    const r = _v0.x.toFixed( 4 );
    const g = _v0.y.toFixed( 4 );
    const b = _v0.z.toFixed( 4 );

    return [

        'float luminance( const in vec3 rgb ) {',

        `   const vec3 weights = vec3( ${ r }, ${ g }, ${ b } );`,

        '   return dot( weights, rgb );',

        '}'

    ].join( '\n' );

}

generateVertexExtensions(parameters: any): string

Parameters:

  • parameters any

Returns: string

Calls:

  • chunks.filter( filterEmptyLine ).join
Code
function generateVertexExtensions( parameters ) {

    const chunks = [
        parameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '',
        parameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '',
    ];

    return chunks.filter( filterEmptyLine ).join( '\n' );

}

generateDefines(defines: any): string

Parameters:

  • defines any

Returns: string

Calls:

  • chunks.push
  • chunks.join
Code
function generateDefines( defines ) {

    const chunks = [];

    for ( const name in defines ) {

        const value = defines[ name ];

        if ( value === false ) continue;

        chunks.push( '#define ' + name + ' ' + value );

    }

    return chunks.join( '\n' );

}

fetchAttributeLocations(gl: any, program: any): {}

Parameters:

  • gl any
  • program any

Returns: {}

Calls:

  • gl.getProgramParameter
  • gl.getActiveAttrib
  • gl.getAttribLocation

Internal Comments:

// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i ); (x4)

Code
function fetchAttributeLocations( gl, program ) {

    const attributes = {};

    const n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );

    for ( let i = 0; i < n; i ++ ) {

        const info = gl.getActiveAttrib( program, i );
        const name = info.name;

        let locationSize = 1;
        if ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;
        if ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;
        if ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;

        // console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );

        attributes[ name ] = {
            type: info.type,
            location: gl.getAttribLocation( program, name ),
            locationSize: locationSize
        };

    }

    return attributes;

}

filterEmptyLine(string: any): boolean

Parameters:

  • string any

Returns: boolean

Code
function filterEmptyLine( string ) {

    return string !== '';

}

replaceLightNums(string: any, parameters: any): any

Parameters:

  • string any
  • parameters any

Returns: any

Calls:

  • string .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights ) .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights ) .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps ) .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords ) .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights ) .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights ) .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights ) .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows ) .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps ) .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows ) .replace
Code
function replaceLightNums( string, parameters ) {

    const numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;

    return string
        .replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )
        .replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )
        .replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )
        .replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )
        .replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )
        .replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )
        .replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )
        .replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )
        .replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )
        .replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )
        .replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );

}

replaceClippingPlaneNums(string: any, parameters: any): any

Parameters:

  • string any
  • parameters any

Returns: any

Calls:

  • string .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes ) .replace
Code
function replaceClippingPlaneNums( string, parameters ) {

    return string
        .replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )
        .replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );

}

resolveIncludes(string: any): any

Parameters:

  • string any

Returns: any

Calls:

  • string.replace
Code
function resolveIncludes( string ) {

    return string.replace( includePattern, includeReplacer );

}

includeReplacer(match: any, include: any): any

Parameters:

  • match any
  • include any

Returns: any

Calls:

  • shaderChunkMap.get
  • console.warn
  • resolveIncludes
Code
function includeReplacer( match, include ) {

    let string = ShaderChunk[ include ];

    if ( string === undefined ) {

        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 + '>' );

        }

    }

    return resolveIncludes( string );

}

unrollLoops(string: any): any

Parameters:

  • string any

Returns: any

Calls:

  • string.replace
Code
function unrollLoops( string ) {

    return string.replace( unrollLoopPattern, loopReplacer );

}

loopReplacer(match: any, start: any, end: any, snippet: any): string

Parameters:

  • match any
  • start any
  • end any
  • snippet any

Returns: string

Calls:

  • parseInt
  • snippet .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' ) .replace
Code
function loopReplacer( match, start, end, snippet ) {

    let string = '';

    for ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {

        string += snippet
            .replace( /\[\s*i\s*\]/g, '[ ' + i + ' ]' )
            .replace( /UNROLLED_LOOP_INDEX/g, i );

    }

    return string;

}

generatePrecision(parameters: any): string

Parameters:

  • parameters any

Returns: string

Code
function generatePrecision( parameters ) {

    let precisionstring = `precision ${parameters.precision} float;
    precision ${parameters.precision} int;
    precision ${parameters.precision} sampler2D;
    precision ${parameters.precision} samplerCube;
    precision ${parameters.precision} sampler3D;
    precision ${parameters.precision} sampler2DArray;
    precision ${parameters.precision} sampler2DShadow;
    precision ${parameters.precision} samplerCubeShadow;
    precision ${parameters.precision} sampler2DArrayShadow;
    precision ${parameters.precision} isampler2D;
    precision ${parameters.precision} isampler3D;
    precision ${parameters.precision} isamplerCube;
    precision ${parameters.precision} isampler2DArray;
    precision ${parameters.precision} usampler2D;
    precision ${parameters.precision} usampler3D;
    precision ${parameters.precision} usamplerCube;
    precision ${parameters.precision} usampler2DArray;
    `;

    if ( parameters.precision === 'highp' ) {

        precisionstring += '\n#define HIGH_PRECISION';

    } else if ( parameters.precision === 'mediump' ) {

        precisionstring += '\n#define MEDIUM_PRECISION';

    } else if ( parameters.precision === 'lowp' ) {

        precisionstring += '\n#define LOW_PRECISION';

    }

    return precisionstring;

}

generateShadowMapTypeDefine(parameters: any): string

Parameters:

  • parameters any

Returns: string

Code
function generateShadowMapTypeDefine( parameters ) {

    let shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';

    if ( parameters.shadowMapType === PCFShadowMap ) {

        shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';

    } else if ( parameters.shadowMapType === PCFSoftShadowMap ) {

        shadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';

    } else if ( parameters.shadowMapType === VSMShadowMap ) {

        shadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';

    }

    return shadowMapTypeDefine;

}

generateEnvMapTypeDefine(parameters: any): string

Parameters:

  • parameters any

Returns: string

Code
function generateEnvMapTypeDefine( parameters ) {

    let envMapTypeDefine = 'ENVMAP_TYPE_CUBE';

    if ( parameters.envMap ) {

        switch ( parameters.envMapMode ) {

            case CubeReflectionMapping:
            case CubeRefractionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_CUBE';
                break;

            case CubeUVReflectionMapping:
                envMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';
                break;

        }

    }

    return envMapTypeDefine;

}

generateEnvMapModeDefine(parameters: any): string

Parameters:

  • parameters any

Returns: string

Code
function generateEnvMapModeDefine( parameters ) {

    let envMapModeDefine = 'ENVMAP_MODE_REFLECTION';

    if ( parameters.envMap ) {

        switch ( parameters.envMapMode ) {

            case CubeRefractionMapping:

                envMapModeDefine = 'ENVMAP_MODE_REFRACTION';
                break;

        }

    }

    return envMapModeDefine;

}

generateEnvMapBlendingDefine(parameters: any): string

Parameters:

  • parameters any

Returns: string

Code
function generateEnvMapBlendingDefine( parameters ) {

    let envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';

    if ( parameters.envMap ) {

        switch ( parameters.combine ) {

            case MultiplyOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';
                break;

            case MixOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_MIX';
                break;

            case AddOperation:
                envMapBlendingDefine = 'ENVMAP_BLENDING_ADD';
                break;

        }

    }

    return envMapBlendingDefine;

}

generateCubeUVSize(parameters: any): { texelWidth: number; texelHeight: number; maxMip: number; }

Parameters:

  • parameters any

Returns: { texelWidth: number; texelHeight: number; maxMip: number; }

Calls:

  • Math.log2
  • Math.max
  • Math.pow
Code
function generateCubeUVSize( parameters ) {

    const imageHeight = parameters.envMapCubeUVHeight;

    if ( imageHeight === null ) return null;

    const maxMip = Math.log2( imageHeight ) - 2;

    const texelHeight = 1.0 / imageHeight;

    const texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );

    return { texelWidth, texelHeight, maxMip };

}

WebGLProgram(renderer: any, cacheKey: any, parameters: any, bindingStates: any): this

Parameters:

  • renderer any
  • cacheKey any
  • parameters any
  • bindingStates any

Returns: this

Calls:

  • renderer.getContext
  • generateShadowMapTypeDefine
  • generateEnvMapTypeDefine
  • generateEnvMapModeDefine
  • generateEnvMapBlendingDefine
  • generateCubeUVSize
  • generateVertexExtensions
  • generateDefines
  • gl.createProgram
  • `[
        '#define SHADER_TYPE ' + parameters.shaderType,
        '#define SHADER_NAME ' + parameters.shaderName,
    
        customDefines
    
    ].filter( filterEmptyLine ).join`
    
    • `[

      generatePrecision( parameters ),
      
      '#define SHADER_TYPE ' + parameters.shaderType,
      '#define SHADER_NAME ' + parameters.shaderName,
      
      customDefines,
      
      parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
      parameters.batching ? '#define USE_BATCHING' : '',
      parameters.batchingColor ? '#define USE_BATCHING_COLOR' : '',
      parameters.instancing ? '#define USE_INSTANCING' : '',
      parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
      parameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '',
      
      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.bumpMap ? '#define USE_BUMPMAP' : '',
      parameters.normalMap ? '#define USE_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' : '',
      parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
      
      parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
      parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
      
      parameters.specularMap ? '#define USE_SPECULARMAP' : '',
      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_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.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.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' : '',
      
      parameters.skinning ? '#define USE_SKINNING' : '',
      
      parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
      parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
      ( parameters.morphColors ) ? '#define USE_MORPHCOLORS' : '',
      ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
      ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
      parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
      parameters.flipSided ? '#define FLIP_SIDED' : '',
      
      parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
      parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
      
      parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',
      
      parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
      
      parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
      parameters.reversedDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
      
      'uniform mat4 modelMatrix;',
      'uniform mat4 modelViewMatrix;',
      'uniform mat4 projectionMatrix;',
      'uniform mat4 viewMatrix;',
      'uniform mat3 normalMatrix;',
      'uniform vec3 cameraPosition;',
      'uniform bool isOrthographic;',
      
      '#ifdef USE_INSTANCING',
      
      '   attribute mat4 instanceMatrix;',
      
      '#endif',
      
      '#ifdef USE_INSTANCING_COLOR',
      
      '   attribute vec3 instanceColor;',
      
      '#endif',
      
      '#ifdef USE_INSTANCING_MORPH',
      
      '   uniform sampler2D morphTexture;',
      
      '#endif',
      
      'attribute vec3 position;',
      '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;',
      
      '#endif',
      
      '#if defined( USE_COLOR_ALPHA )',
      
      '   attribute vec4 color;',
      
      '#elif defined( USE_COLOR )',
      
      '   attribute vec3 color;',
      
      '#endif',
      
      '#ifdef USE_SKINNING',
      
      '   attribute vec4 skinIndex;',
      '   attribute vec4 skinWeight;',
      
      '#endif',
      
      '\n'
      

      ].filter( filterEmptyLine ).join-[

      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.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '',
      parameters.map ? '#define USE_MAP' : '',
      parameters.matcap ? '#define USE_MATCAP' : '',
      parameters.envMap ? '#define USE_ENVMAP' : '',
      parameters.envMap ? '#define ' + envMapTypeDefine : '',
      parameters.envMap ? '#define ' + envMapModeDefine : '',
      parameters.envMap ? '#define ' + envMapBlendingDefine : '',
      envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
      envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
      envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
      parameters.lightMap ? '#define USE_LIGHTMAP' : '',
      parameters.aoMap ? '#define USE_AOMAP' : '',
      parameters.bumpMap ? '#define USE_BUMPMAP' : '',
      parameters.normalMap ? '#define USE_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' : '',
      parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
      parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',
      
      parameters.dispersion ? '#define USE_DISPERSION' : '',
      
      parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
      parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
      parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',
      
      parameters.specularMap ? '#define USE_SPECULARMAP' : '',
      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_SHEEN_COLORMAP' : '',
      parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',
      
      parameters.transmission ? '#define USE_TRANSMISSION' : '',
      parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
      parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',
      
      parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
      parameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '',
      parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
      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' : '',
      
      parameters.flatShading ? '#define FLAT_SHADED' : '',
      
      parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
      parameters.flipSided ? '#define FLIP_SIDED' : '',
      
      parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
      parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',
      
      parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',
      
      parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',
      
      parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
      parameters.decodeVideoTextureEmissive ? '#define DECODE_VIDEO_TEXTURE_EMISSIVE' : '',
      
      parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
      parameters.reversedDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',
      
      'uniform mat4 viewMatrix;',
      'uniform vec3 cameraPosition;',
      'uniform bool isOrthographic;',
      
      ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
      ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
      ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',
      
      parameters.dithering ? '#define DITHERING' : '',
      parameters.opaque ? '#define OPAQUE' : '',
      
      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 ),
      getLuminanceFunction(),
      
      parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',
      
      '\n'
      

      ].filter( filterEmptyLine ).join-resolveIncludes-replaceLightNums-replaceClippingPlaneNums-unrollLoops-[ customVertexExtensions, '#define attribute in', '#define varying out', '#define texture2D texture' ].join-[ '#define varying in', ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;', ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor', '#define gl_FragDepthEXT gl_FragDepth', '#define texture2D texture', '#define textureCube texture', '#define texture2DProj textureProj', '#define texture2DLodEXT textureLod', '#define texture2DProjLodEXT textureProjLod', '#define textureCubeLodEXT textureLod', '#define texture2DGradEXT textureGrad', '#define texture2DProjGradEXT textureProjGrad', '#define textureCubeGradEXT textureGrad' ].join-WebGLShader-gl.attachShader-gl.bindAttribLocation-gl.linkProgram-gl.getProgramInfoLog-gl.getShaderInfoLog-programInfoLog.trim-vertexShaderInfoLog.trim-fragmentShaderInfoLog.trim-gl.getProgramParameter-renderer.debug.onShaderError-getShaderErrors-console.error-gl.getError-console.warn-gl.deleteShader-fetchAttributeLocations-onFirstUse-bindingStates.releaseStatesOfProgram-gl.deleteProgram`

Internal Comments:

// TODO Send this event to Three.js DevTools (x2)
// console.log( 'WebGLProgram', cacheKey ); (x2)
// (x11)
// GLSL 3.0 conversion for built-in materials and ShaderMaterial (x3)
// console.log( '*VERTEX*', vertexGlsl ); (x2)
// console.log( '*FRAGMENT*', fragmentGlsl ); (x2)
// Force a particular attribute to index 0.
// programs with morphTargets displace position out of attribute 0 (x4)
// check for link errors
// default error reporting (x2)
// Clean up (x4)
// Crashes in iOS9 and iOS10. #18402 (x4)
// gl.detachShader( program, glVertexShader ); (x4)
// gl.detachShader( program, glFragmentShader ); (x4)
// set up caching for uniform locations (x2)
// Populates cachedUniforms and cachedAttributes (x3)
// set up caching for attribute locations (x2)
// Populates cachedAttributes and cachedUniforms (x3)
// indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported, (x2)
// flag the program as ready immediately. It may cause a stall when it's first used. (x2)
// free resource (x4)

Code
function WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {

    // TODO Send this event to Three.js DevTools
    // console.log( 'WebGLProgram', cacheKey );

    const gl = renderer.getContext();

    const defines = parameters.defines;

    let vertexShader = parameters.vertexShader;
    let fragmentShader = parameters.fragmentShader;

    const shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );
    const envMapTypeDefine = generateEnvMapTypeDefine( parameters );
    const envMapModeDefine = generateEnvMapModeDefine( parameters );
    const envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );
    const envMapCubeUVSize = generateCubeUVSize( parameters );

    const customVertexExtensions = generateVertexExtensions( parameters );

    const customDefines = generateDefines( defines );

    const program = gl.createProgram();

    let prefixVertex, prefixFragment;
    let versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\n' : '';

    if ( parameters.isRawShaderMaterial ) {

        prefixVertex = [

            '#define SHADER_TYPE ' + parameters.shaderType,
            '#define SHADER_NAME ' + parameters.shaderName,

            customDefines

        ].filter( filterEmptyLine ).join( '\n' );

        if ( prefixVertex.length > 0 ) {

            prefixVertex += '\n';

        }

        prefixFragment = [

            '#define SHADER_TYPE ' + parameters.shaderType,
            '#define SHADER_NAME ' + parameters.shaderName,

            customDefines

        ].filter( filterEmptyLine ).join( '\n' );

        if ( prefixFragment.length > 0 ) {

            prefixFragment += '\n';

        }

    } else {

        prefixVertex = [

            generatePrecision( parameters ),

            '#define SHADER_TYPE ' + parameters.shaderType,
            '#define SHADER_NAME ' + parameters.shaderName,

            customDefines,

            parameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',
            parameters.batching ? '#define USE_BATCHING' : '',
            parameters.batchingColor ? '#define USE_BATCHING_COLOR' : '',
            parameters.instancing ? '#define USE_INSTANCING' : '',
            parameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',
            parameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '',

            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.bumpMap ? '#define USE_BUMPMAP' : '',
            parameters.normalMap ? '#define USE_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' : '',
            parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',

            parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
            parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',

            parameters.specularMap ? '#define USE_SPECULARMAP' : '',
            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_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.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.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' : '',

            parameters.skinning ? '#define USE_SKINNING' : '',

            parameters.morphTargets ? '#define USE_MORPHTARGETS' : '',
            parameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',
            ( parameters.morphColors ) ? '#define USE_MORPHCOLORS' : '',
            ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',
            ( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',
            parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
            parameters.flipSided ? '#define FLIP_SIDED' : '',

            parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
            parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',

            parameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',

            parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',

            parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
            parameters.reversedDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',

            'uniform mat4 modelMatrix;',
            'uniform mat4 modelViewMatrix;',
            'uniform mat4 projectionMatrix;',
            'uniform mat4 viewMatrix;',
            'uniform mat3 normalMatrix;',
            'uniform vec3 cameraPosition;',
            'uniform bool isOrthographic;',

            '#ifdef USE_INSTANCING',

            '   attribute mat4 instanceMatrix;',

            '#endif',

            '#ifdef USE_INSTANCING_COLOR',

            '   attribute vec3 instanceColor;',

            '#endif',

            '#ifdef USE_INSTANCING_MORPH',

            '   uniform sampler2D morphTexture;',

            '#endif',

            'attribute vec3 position;',
            '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;',

            '#endif',

            '#if defined( USE_COLOR_ALPHA )',

            '   attribute vec4 color;',

            '#elif defined( USE_COLOR )',

            '   attribute vec3 color;',

            '#endif',

            '#ifdef USE_SKINNING',

            '   attribute vec4 skinIndex;',
            '   attribute vec4 skinWeight;',

            '#endif',

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

        prefixFragment = [

            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.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '',
            parameters.map ? '#define USE_MAP' : '',
            parameters.matcap ? '#define USE_MATCAP' : '',
            parameters.envMap ? '#define USE_ENVMAP' : '',
            parameters.envMap ? '#define ' + envMapTypeDefine : '',
            parameters.envMap ? '#define ' + envMapModeDefine : '',
            parameters.envMap ? '#define ' + envMapBlendingDefine : '',
            envMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',
            envMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',
            envMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',
            parameters.lightMap ? '#define USE_LIGHTMAP' : '',
            parameters.aoMap ? '#define USE_AOMAP' : '',
            parameters.bumpMap ? '#define USE_BUMPMAP' : '',
            parameters.normalMap ? '#define USE_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' : '',
            parameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',
            parameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',

            parameters.dispersion ? '#define USE_DISPERSION' : '',

            parameters.iridescence ? '#define USE_IRIDESCENCE' : '',
            parameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',
            parameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',

            parameters.specularMap ? '#define USE_SPECULARMAP' : '',
            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_SHEEN_COLORMAP' : '',
            parameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',

            parameters.transmission ? '#define USE_TRANSMISSION' : '',
            parameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',
            parameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',

            parameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',
            parameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '',
            parameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',
            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' : '',

            parameters.flatShading ? '#define FLAT_SHADED' : '',

            parameters.doubleSided ? '#define DOUBLE_SIDED' : '',
            parameters.flipSided ? '#define FLIP_SIDED' : '',

            parameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',
            parameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',

            parameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',

            parameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',

            parameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',
            parameters.decodeVideoTextureEmissive ? '#define DECODE_VIDEO_TEXTURE_EMISSIVE' : '',

            parameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',
            parameters.reversedDepthBuffer ? '#define USE_REVERSEDEPTHBUF' : '',

            'uniform mat4 viewMatrix;',
            'uniform vec3 cameraPosition;',
            'uniform bool isOrthographic;',

            ( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',
            ( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below
            ( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',

            parameters.dithering ? '#define DITHERING' : '',
            parameters.opaque ? '#define OPAQUE' : '',

            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 ),
            getLuminanceFunction(),

            parameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',

            '\n'

        ].filter( filterEmptyLine ).join( '\n' );

    }

    vertexShader = resolveIncludes( vertexShader );
    vertexShader = replaceLightNums( vertexShader, parameters );
    vertexShader = replaceClippingPlaneNums( vertexShader, parameters );

    fragmentShader = resolveIncludes( fragmentShader );
    fragmentShader = replaceLightNums( fragmentShader, parameters );
    fragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );

    vertexShader = unrollLoops( vertexShader );
    fragmentShader = unrollLoops( fragmentShader );

    if ( parameters.isRawShaderMaterial !== true ) {

        // GLSL 3.0 conversion for built-in materials and ShaderMaterial

        versionString = '#version 300 es\n';

        prefixVertex = [
            customVertexExtensions,
            '#define attribute in',
            '#define varying out',
            '#define texture2D texture'
        ].join( '\n' ) + '\n' + prefixVertex;

        prefixFragment = [
            '#define varying in',
            ( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',
            ( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',
            '#define gl_FragDepthEXT gl_FragDepth',
            '#define texture2D texture',
            '#define textureCube texture',
            '#define texture2DProj textureProj',
            '#define texture2DLodEXT textureLod',
            '#define texture2DProjLodEXT textureProjLod',
            '#define textureCubeLodEXT textureLod',
            '#define texture2DGradEXT textureGrad',
            '#define texture2DProjGradEXT textureProjGrad',
            '#define textureCubeGradEXT textureGrad'
        ].join( '\n' ) + '\n' + prefixFragment;

    }

    const vertexGlsl = versionString + prefixVertex + vertexShader;
    const fragmentGlsl = versionString + prefixFragment + fragmentShader;

    // console.log( '*VERTEX*', vertexGlsl );
    // console.log( '*FRAGMENT*', 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 );

    // Force a particular attribute to index 0.

    if ( parameters.index0AttributeName !== undefined ) {

        gl.bindAttribLocation( program, 0, parameters.index0AttributeName );

    } else if ( parameters.morphTargets === true ) {

        // programs with morphTargets displace position out of attribute 0
        gl.bindAttribLocation( program, 0, 'position' );

    }

    gl.linkProgram( program );

    function onFirstUse( self ) {

        // check for link errors
        if ( renderer.debug.checkShaderErrors ) {

            const programInfoLog = gl.getProgramInfoLog( program ) || '';
            const vertexShaderInfoLog = gl.getShaderInfoLog( glVertexShader ) || '';
            const fragmentShaderInfoLog = gl.getShaderInfoLog( glFragmentShader ) || '';

            const programLog = programInfoLog.trim();
            const vertexLog = vertexShaderInfoLog.trim();
            const fragmentLog = fragmentShaderInfoLog.trim();

            let runnable = true;
            let haveDiagnostics = true;

            if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {

                runnable = false;

                if ( typeof renderer.debug.onShaderError === 'function' ) {

                    renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );

                } else {

                    // default error reporting

                    const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
                    const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );

                    console.error(
                        'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
                        'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
                        'Material Name: ' + self.name + '\n' +
                        'Material Type: ' + self.type + '\n\n' +
                        'Program Info Log: ' + programLog + '\n' +
                        vertexErrors + '\n' +
                        fragmentErrors
                    );

                }

            } else if ( programLog !== '' ) {

                console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );

            } else if ( vertexLog === '' || fragmentLog === '' ) {

                haveDiagnostics = false;

            }

            if ( haveDiagnostics ) {

                self.diagnostics = {

                    runnable: runnable,

                    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 );

        gl.deleteShader( glVertexShader );
        gl.deleteShader( glFragmentShader );

        cachedUniforms = new WebGLUniforms( gl, program );
        cachedAttributes = fetchAttributeLocations( gl, program );

    }

    // set up caching for uniform locations

    let cachedUniforms;

    this.getUniforms = function () {

        if ( cachedUniforms === undefined ) {

            // Populates cachedUniforms and cachedAttributes
            onFirstUse( this );

        }

        return cachedUniforms;

    };

    // set up caching for attribute locations

    let cachedAttributes;

    this.getAttributes = function () {

        if ( cachedAttributes === undefined ) {

            // Populates cachedAttributes and cachedUniforms
            onFirstUse( this );

        }

        return cachedAttributes;

    };

    // 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 () {

        bindingStates.releaseStatesOfProgram( this );

        gl.deleteProgram( program );
        this.program = undefined;

    };

    //

    this.type = parameters.shaderType;
    this.name = parameters.shaderName;
    this.id = programIdCount ++;
    this.cacheKey = cacheKey;
    this.usedTimes = 1;
    this.program = program;
    this.vertexShader = glVertexShader;
    this.fragmentShader = glFragmentShader;

    return this;

}

onFirstUse(self: any): void

Parameters:

  • self any

Returns: void

Calls:

  • gl.getProgramInfoLog
  • gl.getShaderInfoLog
  • programInfoLog.trim
  • vertexShaderInfoLog.trim
  • fragmentShaderInfoLog.trim
  • gl.getProgramParameter
  • renderer.debug.onShaderError
  • getShaderErrors
  • console.error
  • gl.getError
  • console.warn
  • gl.deleteShader
  • fetchAttributeLocations

Internal Comments:

// check for link errors
// default error reporting (x2)
// Clean up (x4)
// Crashes in iOS9 and iOS10. #18402 (x4)
// gl.detachShader( program, glVertexShader ); (x4)
// gl.detachShader( program, glFragmentShader ); (x4)

Code
function onFirstUse( self ) {

        // check for link errors
        if ( renderer.debug.checkShaderErrors ) {

            const programInfoLog = gl.getProgramInfoLog( program ) || '';
            const vertexShaderInfoLog = gl.getShaderInfoLog( glVertexShader ) || '';
            const fragmentShaderInfoLog = gl.getShaderInfoLog( glFragmentShader ) || '';

            const programLog = programInfoLog.trim();
            const vertexLog = vertexShaderInfoLog.trim();
            const fragmentLog = fragmentShaderInfoLog.trim();

            let runnable = true;
            let haveDiagnostics = true;

            if ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {

                runnable = false;

                if ( typeof renderer.debug.onShaderError === 'function' ) {

                    renderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );

                } else {

                    // default error reporting

                    const vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );
                    const fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );

                    console.error(
                        'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +
                        'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\n\n' +
                        'Material Name: ' + self.name + '\n' +
                        'Material Type: ' + self.type + '\n\n' +
                        'Program Info Log: ' + programLog + '\n' +
                        vertexErrors + '\n' +
                        fragmentErrors
                    );

                }

            } else if ( programLog !== '' ) {

                console.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );

            } else if ( vertexLog === '' || fragmentLog === '' ) {

                haveDiagnostics = false;

            }

            if ( haveDiagnostics ) {

                self.diagnostics = {

                    runnable: runnable,

                    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 );

        gl.deleteShader( glVertexShader );
        gl.deleteShader( glFragmentShader );

        cachedUniforms = new WebGLUniforms( gl, program );
        cachedAttributes = fetchAttributeLocations( gl, program );

    }

WebGLShaderCache.update(material: any): this

Parameters:

  • material any

Returns: this

Calls:

  • this._getShaderStage
  • this._getShaderCacheForMaterial
  • materialShaders.has
  • materialShaders.add
Code
update( material ) {

        const vertexShader = material.vertexShader;
        const fragmentShader = material.fragmentShader;

        const vertexShaderStage = this._getShaderStage( vertexShader );
        const fragmentShaderStage = this._getShaderStage( fragmentShader );

        const materialShaders = this._getShaderCacheForMaterial( material );

        if ( materialShaders.has( vertexShaderStage ) === false ) {

            materialShaders.add( vertexShaderStage );
            vertexShaderStage.usedTimes ++;

        }

        if ( materialShaders.has( fragmentShaderStage ) === false ) {

            materialShaders.add( fragmentShaderStage );
            fragmentShaderStage.usedTimes ++;

        }

        return this;

    }

WebGLShaderCache.remove(material: any): this

Parameters:

  • material any

Returns: this

Calls:

  • this.materialCache.get
  • this.shaderCache.delete
  • this.materialCache.delete
Code
remove( material ) {

        const materialShaders = this.materialCache.get( material );

        for ( const shaderStage of materialShaders ) {

            shaderStage.usedTimes --;

            if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );

        }

        this.materialCache.delete( material );

        return this;

    }

WebGLShaderCache.getVertexShaderID(material: any): any

Parameters:

  • material any

Returns: any

Calls:

  • this._getShaderStage
Code
getVertexShaderID( material ) {

        return this._getShaderStage( material.vertexShader ).id;

    }

WebGLShaderCache.getFragmentShaderID(material: any): any

Parameters:

  • material any

Returns: any

Calls:

  • this._getShaderStage
Code
getFragmentShaderID( material ) {

        return this._getShaderStage( material.fragmentShader ).id;

    }

WebGLShaderCache.dispose(): void

Returns: void

Calls:

  • this.shaderCache.clear
  • this.materialCache.clear
Code
dispose() {

        this.shaderCache.clear();
        this.materialCache.clear();

    }

WebGLShaderCache._getShaderCacheForMaterial(material: any): any

Parameters:

  • material any

Returns: any

Calls:

  • cache.get
  • cache.set
Code
_getShaderCacheForMaterial( material ) {

        const cache = this.materialCache;
        let set = cache.get( material );

        if ( set === undefined ) {

            set = new Set();
            cache.set( material, set );

        }

        return set;

    }

WebGLShaderCache._getShaderStage(code: any): any

Parameters:

  • code any

Returns: any

Calls:

  • cache.get
  • cache.set
Code
_getShaderStage( code ) {

        const cache = this.shaderCache;
        let stage = cache.get( code );

        if ( stage === undefined ) {

            stage = new WebGLShaderStage( code );
            cache.set( code, stage );

        }

        return stage;

    }

WebGLPrograms(renderer: any, cubemaps: any, cubeuvmaps: any, extensions: any, capabilities: any, bindingStates: any, clipping: any): { getParameters: (material: any, lights: any, shadows: any, scene: any, object: any) => { shaderID: any; shaderType: any; shaderName: any; vertexShader: any; fragmentShader: any; defines: any; ... 121 more ...; customProgramCacheKey: any; }; ... 6 more ...; dispose: () => void; }

Parameters:

  • renderer any
  • cubemaps any
  • cubeuvmaps any
  • extensions any
  • capabilities any
  • bindingStates any
  • clipping any

Returns: { getParameters: (material: any, lights: any, shadows: any, scene: any, object: any) => { shaderID: any; shaderType: any; shaderName: any; vertexShader: any; fragmentShader: any; defines: any; ... 121 more ...; customProgramCacheKey: any; }; ... 6 more ...; dispose: () => void; }

Calls:

  • _activeChannels.add
  • ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get
  • capabilities.getMaxPrecision
  • console.warn
  • _customShaders.update
  • _customShaders.getVertexShaderID
  • _customShaders.getFragmentShaderID
  • renderer.getRenderTarget
  • renderer.state.buffers.depth.getReversed
  • getChannel
  • ColorManagement.getTransfer
  • extensions.has
  • material.customProgramCacheKey
  • _activeChannels.has
  • _activeChannels.clear
  • array.push
  • getProgramCacheKeyParameters
  • getProgramCacheKeyBooleans
  • array.join
  • _programLayers.disableAll
  • _programLayers.enable
  • UniformsUtils.clone
  • programs.push
  • programs.indexOf
  • programs.pop
  • program.destroy
  • _customShaders.remove
  • _customShaders.dispose

Internal Comments:

// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
// (x8)
// the usage of getChannel() determines the active texture channels for this shader (x4)
// Check if code has been already compiled
// Remove from unordered set (x2)
// Free WebGL resources (x4)
// Exposed for resource monitoring & error feedback via renderer.info: (x2)

Code
function WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {

    const _programLayers = new Layers();
    const _customShaders = new WebGLShaderCache();
    const _activeChannels = new Set();
    const programs = [];

    const logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;
    const SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;

    let precision = capabilities.precision;

    const shaderIDs = {
        MeshDepthMaterial: 'depth',
        MeshDistanceMaterial: 'distanceRGBA',
        MeshNormalMaterial: 'normal',
        MeshBasicMaterial: 'basic',
        MeshLambertMaterial: 'lambert',
        MeshPhongMaterial: 'phong',
        MeshToonMaterial: 'toon',
        MeshStandardMaterial: 'physical',
        MeshPhysicalMaterial: 'physical',
        MeshMatcapMaterial: 'matcap',
        LineBasicMaterial: 'basic',
        LineDashedMaterial: 'dashed',
        PointsMaterial: 'points',
        ShadowMaterial: 'shadow',
        SpriteMaterial: 'sprite'
    };

    function getChannel( value ) {

        _activeChannels.add( value );

        if ( value === 0 ) return 'uv';

        return `uv${ value }`;

    }

    function getParameters( material, lights, shadows, scene, object ) {

        const fog = scene.fog;
        const geometry = object.geometry;
        const environment = material.isMeshStandardMaterial ? scene.environment : null;

        const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
        const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;

        const shaderID = shaderIDs[ material.type ];

        // heuristics to create shader parameters according to lights in the scene
        // (not to blow over maxLights budget)

        if ( material.precision !== null ) {

            precision = capabilities.getMaxPrecision( material.precision );

            if ( precision !== material.precision ) {

                console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );

            }

        }

        //

        const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
        const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

        let morphTextureStride = 0;

        if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
        if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
        if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;

        //

        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 reversedDepthBuffer = renderer.state.buffers.depth.getReversed();

        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_DISPERSION = material.dispersion > 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;

        let toneMapping = NoToneMapping;

        if ( material.toneMapped ) {

            if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {

                toneMapping = renderer.toneMapping;

            }

        }

        const parameters = {

            shaderID: shaderID,
            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,
            batchingColor: IS_BATCHEDMESH && object._colorsTexture !== null,
            instancing: IS_INSTANCEDMESH,
            instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
            instancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null,

            supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,
            outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
            alphaToCoverage: !! material.alphaToCoverage,

            map: HAS_MAP,
            matcap: HAS_MATCAP,
            envMap: HAS_ENVMAP,
            envMapMode: HAS_ENVMAP && envMap.mapping,
            envMapCubeUVHeight: envMapCubeUVHeight,
            aoMap: HAS_AOMAP,
            lightMap: HAS_LIGHTMAP,
            bumpMap: HAS_BUMPMAP,
            normalMap: HAS_NORMALMAP,
            displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,
            emissiveMap: HAS_EMISSIVEMAP,

            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,

            dispersion: HAS_DISPERSION,

            iridescence: HAS_IRIDESCENCE,
            iridescenceMap: HAS_IRIDESCENCEMAP,
            iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,

            sheen: HAS_SHEEN,
            sheenColorMap: HAS_SHEEN_COLORMAP,
            sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,

            specularMap: HAS_SPECULARMAP,
            specularColorMap: HAS_SPECULAR_COLORMAP,
            specularIntensityMap: HAS_SPECULAR_INTENSITYMAP,

            transmission: HAS_TRANSMISSION,
            transmissionMap: HAS_TRANSMISSIONMAP,
            thicknessMap: HAS_THICKNESSMAP,

            gradientMap: HAS_GRADIENTMAP,

            opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false,

            alphaMap: HAS_ALPHAMAP,
            alphaTest: HAS_ALPHATEST,
            alphaHash: HAS_ALPHAHASH,

            combine: material.combine,

            //

            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,

            pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),

            fog: !! fog,
            useFog: material.fog === true,
            fogExp2: ( !! fog && fog.isFogExp2 ),

            flatShading: ( material.flatShading === true && material.wireframe === false ),

            sizeAttenuation: material.sizeAttenuation === true,
            logarithmicDepthBuffer: logarithmicDepthBuffer,
            reversedDepthBuffer: reversedDepthBuffer,

            skinning: object.isSkinnedMesh === true,

            morphTargets: geometry.morphAttributes.position !== undefined,
            morphNormals: geometry.morphAttributes.normal !== undefined,
            morphColors: geometry.morphAttributes.color !== undefined,
            morphTargetsCount: morphTargetsCount,
            morphTextureStride: morphTextureStride,

            numDirLights: lights.directional.length,
            numPointLights: lights.point.length,
            numSpotLights: lights.spot.length,
            numSpotLightMaps: lights.spotLightMap.length,
            numRectAreaLights: lights.rectArea.length,
            numHemiLights: lights.hemi.length,

            numDirLightShadows: lights.directionalShadowMap.length,
            numPointLightShadows: lights.pointShadowMap.length,
            numSpotLightShadows: lights.spotShadowMap.length,
            numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,

            numLightProbes: lights.numLightProbes,

            numClippingPlanes: clipping.numPlanes,
            numClipIntersection: clipping.numIntersection,

            dithering: material.dithering,

            shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
            shadowMapType: renderer.shadowMap.type,

            toneMapping: toneMapping,

            decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),
            decodeVideoTextureEmissive: HAS_EMISSIVEMAP && ( material.emissiveMap.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.emissiveMap.colorSpace ) === SRGBTransfer ),

            premultipliedAlpha: material.premultipliedAlpha,

            doubleSided: material.side === DoubleSide,
            flipSided: material.side === BackSide,

            useDepthPacking: material.depthPacking >= 0,
            depthPacking: material.depthPacking || 0,

            index0AttributeName: material.index0AttributeName,

            extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ),
            extensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ),

            rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),

            customProgramCacheKey: material.customProgramCacheKey()

        };

        // the usage of getChannel() determines the active texture channels for this shader

        parameters.vertexUv1s = _activeChannels.has( 1 );
        parameters.vertexUv2s = _activeChannels.has( 2 );
        parameters.vertexUv3s = _activeChannels.has( 3 );

        _activeChannels.clear();

        return parameters;

    }

    function getProgramCacheKey( parameters ) {

        const array = [];

        if ( parameters.shaderID ) {

            array.push( parameters.shaderID );

        } else {

            array.push( parameters.customVertexShaderID );
            array.push( parameters.customFragmentShaderID );

        }

        if ( parameters.defines !== undefined ) {

            for ( const name in parameters.defines ) {

                array.push( name );
                array.push( parameters.defines[ name ] );

            }

        }

        if ( parameters.isRawShaderMaterial === false ) {

            getProgramCacheKeyParameters( array, parameters );
            getProgramCacheKeyBooleans( array, parameters );
            array.push( renderer.outputColorSpace );

        }

        array.push( parameters.customProgramCacheKey );

        return array.join();

    }

    function getProgramCacheKeyParameters( array, parameters ) {

        array.push( parameters.precision );
        array.push( parameters.outputColorSpace );
        array.push( parameters.envMapMode );
        array.push( parameters.envMapCubeUVHeight );
        array.push( parameters.mapUv );
        array.push( parameters.alphaMapUv );
        array.push( parameters.lightMapUv );
        array.push( parameters.aoMapUv );
        array.push( parameters.bumpMapUv );
        array.push( parameters.normalMapUv );
        array.push( parameters.displacementMapUv );
        array.push( parameters.emissiveMapUv );
        array.push( parameters.metalnessMapUv );
        array.push( parameters.roughnessMapUv );
        array.push( parameters.anisotropyMapUv );
        array.push( parameters.clearcoatMapUv );
        array.push( parameters.clearcoatNormalMapUv );
        array.push( parameters.clearcoatRoughnessMapUv );
        array.push( parameters.iridescenceMapUv );
        array.push( parameters.iridescenceThicknessMapUv );
        array.push( parameters.sheenColorMapUv );
        array.push( parameters.sheenRoughnessMapUv );
        array.push( parameters.specularMapUv );
        array.push( parameters.specularColorMapUv );
        array.push( parameters.specularIntensityMapUv );
        array.push( parameters.transmissionMapUv );
        array.push( parameters.thicknessMapUv );
        array.push( parameters.combine );
        array.push( parameters.fogExp2 );
        array.push( parameters.sizeAttenuation );
        array.push( parameters.morphTargetsCount );
        array.push( parameters.morphAttributeCount );
        array.push( parameters.numDirLights );
        array.push( parameters.numPointLights );
        array.push( parameters.numSpotLights );
        array.push( parameters.numSpotLightMaps );
        array.push( parameters.numHemiLights );
        array.push( parameters.numRectAreaLights );
        array.push( parameters.numDirLightShadows );
        array.push( parameters.numPointLightShadows );
        array.push( parameters.numSpotLightShadows );
        array.push( parameters.numSpotLightShadowsWithMaps );
        array.push( parameters.numLightProbes );
        array.push( parameters.shadowMapType );
        array.push( parameters.toneMapping );
        array.push( parameters.numClippingPlanes );
        array.push( parameters.numClipIntersection );
        array.push( parameters.depthPacking );

    }

    function getProgramCacheKeyBooleans( array, parameters ) {

        _programLayers.disableAll();

        if ( parameters.supportsVertexTextures )
            _programLayers.enable( 0 );
        if ( parameters.instancing )
            _programLayers.enable( 1 );
        if ( parameters.instancingColor )
            _programLayers.enable( 2 );
        if ( parameters.instancingMorph )
            _programLayers.enable( 3 );
        if ( parameters.matcap )
            _programLayers.enable( 4 );
        if ( parameters.envMap )
            _programLayers.enable( 5 );
        if ( parameters.normalMapObjectSpace )
            _programLayers.enable( 6 );
        if ( parameters.normalMapTangentSpace )
            _programLayers.enable( 7 );
        if ( parameters.clearcoat )
            _programLayers.enable( 8 );
        if ( parameters.iridescence )
            _programLayers.enable( 9 );
        if ( parameters.alphaTest )
            _programLayers.enable( 10 );
        if ( parameters.vertexColors )
            _programLayers.enable( 11 );
        if ( parameters.vertexAlphas )
            _programLayers.enable( 12 );
        if ( parameters.vertexUv1s )
            _programLayers.enable( 13 );
        if ( parameters.vertexUv2s )
            _programLayers.enable( 14 );
        if ( parameters.vertexUv3s )
            _programLayers.enable( 15 );
        if ( parameters.vertexTangents )
            _programLayers.enable( 16 );
        if ( parameters.anisotropy )
            _programLayers.enable( 17 );
        if ( parameters.alphaHash )
            _programLayers.enable( 18 );
        if ( parameters.batching )
            _programLayers.enable( 19 );
        if ( parameters.dispersion )
            _programLayers.enable( 20 );
        if ( parameters.batchingColor )
            _programLayers.enable( 21 );
        if ( parameters.gradientMap )
            _programLayers.enable( 22 );

        array.push( _programLayers.mask );
        _programLayers.disableAll();

        if ( parameters.fog )
            _programLayers.enable( 0 );
        if ( parameters.useFog )
            _programLayers.enable( 1 );
        if ( parameters.flatShading )
            _programLayers.enable( 2 );
        if ( parameters.logarithmicDepthBuffer )
            _programLayers.enable( 3 );
        if ( parameters.reversedDepthBuffer )
            _programLayers.enable( 4 );
        if ( parameters.skinning )
            _programLayers.enable( 5 );
        if ( parameters.morphTargets )
            _programLayers.enable( 6 );
        if ( parameters.morphNormals )
            _programLayers.enable( 7 );
        if ( parameters.morphColors )
            _programLayers.enable( 8 );
        if ( parameters.premultipliedAlpha )
            _programLayers.enable( 9 );
        if ( parameters.shadowMapEnabled )
            _programLayers.enable( 10 );
        if ( parameters.doubleSided )
            _programLayers.enable( 11 );
        if ( parameters.flipSided )
            _programLayers.enable( 12 );
        if ( parameters.useDepthPacking )
            _programLayers.enable( 13 );
        if ( parameters.dithering )
            _programLayers.enable( 14 );
        if ( parameters.transmission )
            _programLayers.enable( 15 );
        if ( parameters.sheen )
            _programLayers.enable( 16 );
        if ( parameters.opaque )
            _programLayers.enable( 17 );
        if ( parameters.pointsUvs )
            _programLayers.enable( 18 );
        if ( parameters.decodeVideoTexture )
            _programLayers.enable( 19 );
        if ( parameters.decodeVideoTextureEmissive )
            _programLayers.enable( 20 );
        if ( parameters.alphaToCoverage )
            _programLayers.enable( 21 );

        array.push( _programLayers.mask );

    }

    function getUniforms( material ) {

        const shaderID = shaderIDs[ material.type ];
        let uniforms;

        if ( shaderID ) {

            const shader = ShaderLib[ shaderID ];
            uniforms = UniformsUtils.clone( shader.uniforms );

        } else {

            uniforms = material.uniforms;

        }

        return uniforms;

    }

    function acquireProgram( parameters, cacheKey ) {

        let program;

        // Check if code has been already compiled
        for ( let p = 0, pl = programs.length; p < pl; p ++ ) {

            const preexistingProgram = programs[ p ];

            if ( preexistingProgram.cacheKey === cacheKey ) {

                program = preexistingProgram;
                ++ program.usedTimes;

                break;

            }

        }

        if ( program === undefined ) {

            program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
            programs.push( program );

        }

        return program;

    }

    function releaseProgram( program ) {

        if ( -- program.usedTimes === 0 ) {

            // Remove from unordered set
            const i = programs.indexOf( program );
            programs[ i ] = programs[ programs.length - 1 ];
            programs.pop();

            // Free WebGL resources
            program.destroy();

        }

    }

    function releaseShaderCache( material ) {

        _customShaders.remove( material );

    }

    function dispose() {

        _customShaders.dispose();

    }

    return {
        getParameters: getParameters,
        getProgramCacheKey: getProgramCacheKey,
        getUniforms: getUniforms,
        acquireProgram: acquireProgram,
        releaseProgram: releaseProgram,
        releaseShaderCache: releaseShaderCache,
        // Exposed for resource monitoring & error feedback via renderer.info:
        programs: programs,
        dispose: dispose
    };

}

getChannel(value: any): string

Parameters:

  • value any

Returns: string

Calls:

  • _activeChannels.add
Code
function getChannel( value ) {

        _activeChannels.add( value );

        if ( value === 0 ) return 'uv';

        return `uv${ value }`;

    }

getParameters(material: any, lights: any, shadows: any, scene: any, object: any): { shaderID: any; shaderType: any; shaderName: any; vertexShader: any; fragmentShader: any; defines: any; customVertexShaderID: any; customFragmentShaderID: any; isRawShaderMaterial: boolean; ... 118 more ...; customProgramCacheKey: any; }

Parameters:

  • material any
  • lights any
  • shadows any
  • scene any
  • object any

Returns: { shaderID: any; shaderType: any; shaderName: any; vertexShader: any; fragmentShader: any; defines: any; customVertexShaderID: any; customFragmentShaderID: any; isRawShaderMaterial: boolean; ... 118 more ...; customProgramCacheKey: any; }

Calls:

  • ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get
  • capabilities.getMaxPrecision
  • console.warn
  • _customShaders.update
  • _customShaders.getVertexShaderID
  • _customShaders.getFragmentShaderID
  • renderer.getRenderTarget
  • renderer.state.buffers.depth.getReversed
  • getChannel
  • ColorManagement.getTransfer
  • extensions.has
  • material.customProgramCacheKey
  • _activeChannels.has
  • _activeChannels.clear

Internal Comments:

// heuristics to create shader parameters according to lights in the scene
// (not to blow over maxLights budget)
// (x8)
// the usage of getChannel() determines the active texture channels for this shader (x4)

Code
function getParameters( material, lights, shadows, scene, object ) {

        const fog = scene.fog;
        const geometry = object.geometry;
        const environment = material.isMeshStandardMaterial ? scene.environment : null;

        const envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );
        const envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;

        const shaderID = shaderIDs[ material.type ];

        // heuristics to create shader parameters according to lights in the scene
        // (not to blow over maxLights budget)

        if ( material.precision !== null ) {

            precision = capabilities.getMaxPrecision( material.precision );

            if ( precision !== material.precision ) {

                console.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );

            }

        }

        //

        const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
        const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

        let morphTextureStride = 0;

        if ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;
        if ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;
        if ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;

        //

        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 reversedDepthBuffer = renderer.state.buffers.depth.getReversed();

        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_DISPERSION = material.dispersion > 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;

        let toneMapping = NoToneMapping;

        if ( material.toneMapped ) {

            if ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {

                toneMapping = renderer.toneMapping;

            }

        }

        const parameters = {

            shaderID: shaderID,
            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,
            batchingColor: IS_BATCHEDMESH && object._colorsTexture !== null,
            instancing: IS_INSTANCEDMESH,
            instancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,
            instancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null,

            supportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,
            outputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),
            alphaToCoverage: !! material.alphaToCoverage,

            map: HAS_MAP,
            matcap: HAS_MATCAP,
            envMap: HAS_ENVMAP,
            envMapMode: HAS_ENVMAP && envMap.mapping,
            envMapCubeUVHeight: envMapCubeUVHeight,
            aoMap: HAS_AOMAP,
            lightMap: HAS_LIGHTMAP,
            bumpMap: HAS_BUMPMAP,
            normalMap: HAS_NORMALMAP,
            displacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,
            emissiveMap: HAS_EMISSIVEMAP,

            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,

            dispersion: HAS_DISPERSION,

            iridescence: HAS_IRIDESCENCE,
            iridescenceMap: HAS_IRIDESCENCEMAP,
            iridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,

            sheen: HAS_SHEEN,
            sheenColorMap: HAS_SHEEN_COLORMAP,
            sheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,

            specularMap: HAS_SPECULARMAP,
            specularColorMap: HAS_SPECULAR_COLORMAP,
            specularIntensityMap: HAS_SPECULAR_INTENSITYMAP,

            transmission: HAS_TRANSMISSION,
            transmissionMap: HAS_TRANSMISSIONMAP,
            thicknessMap: HAS_THICKNESSMAP,

            gradientMap: HAS_GRADIENTMAP,

            opaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false,

            alphaMap: HAS_ALPHAMAP,
            alphaTest: HAS_ALPHATEST,
            alphaHash: HAS_ALPHAHASH,

            combine: material.combine,

            //

            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,

            pointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),

            fog: !! fog,
            useFog: material.fog === true,
            fogExp2: ( !! fog && fog.isFogExp2 ),

            flatShading: ( material.flatShading === true && material.wireframe === false ),

            sizeAttenuation: material.sizeAttenuation === true,
            logarithmicDepthBuffer: logarithmicDepthBuffer,
            reversedDepthBuffer: reversedDepthBuffer,

            skinning: object.isSkinnedMesh === true,

            morphTargets: geometry.morphAttributes.position !== undefined,
            morphNormals: geometry.morphAttributes.normal !== undefined,
            morphColors: geometry.morphAttributes.color !== undefined,
            morphTargetsCount: morphTargetsCount,
            morphTextureStride: morphTextureStride,

            numDirLights: lights.directional.length,
            numPointLights: lights.point.length,
            numSpotLights: lights.spot.length,
            numSpotLightMaps: lights.spotLightMap.length,
            numRectAreaLights: lights.rectArea.length,
            numHemiLights: lights.hemi.length,

            numDirLightShadows: lights.directionalShadowMap.length,
            numPointLightShadows: lights.pointShadowMap.length,
            numSpotLightShadows: lights.spotShadowMap.length,
            numSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,

            numLightProbes: lights.numLightProbes,

            numClippingPlanes: clipping.numPlanes,
            numClipIntersection: clipping.numIntersection,

            dithering: material.dithering,

            shadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,
            shadowMapType: renderer.shadowMap.type,

            toneMapping: toneMapping,

            decodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),
            decodeVideoTextureEmissive: HAS_EMISSIVEMAP && ( material.emissiveMap.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.emissiveMap.colorSpace ) === SRGBTransfer ),

            premultipliedAlpha: material.premultipliedAlpha,

            doubleSided: material.side === DoubleSide,
            flipSided: material.side === BackSide,

            useDepthPacking: material.depthPacking >= 0,
            depthPacking: material.depthPacking || 0,

            index0AttributeName: material.index0AttributeName,

            extensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ),
            extensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ),

            rendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),

            customProgramCacheKey: material.customProgramCacheKey()

        };

        // the usage of getChannel() determines the active texture channels for this shader

        parameters.vertexUv1s = _activeChannels.has( 1 );
        parameters.vertexUv2s = _activeChannels.has( 2 );
        parameters.vertexUv3s = _activeChannels.has( 3 );

        _activeChannels.clear();

        return parameters;

    }

getProgramCacheKey(parameters: any): string

Parameters:

  • parameters any

Returns: string

Calls:

  • array.push
  • getProgramCacheKeyParameters
  • getProgramCacheKeyBooleans
  • array.join
Code
function getProgramCacheKey( parameters ) {

        const array = [];

        if ( parameters.shaderID ) {

            array.push( parameters.shaderID );

        } else {

            array.push( parameters.customVertexShaderID );
            array.push( parameters.customFragmentShaderID );

        }

        if ( parameters.defines !== undefined ) {

            for ( const name in parameters.defines ) {

                array.push( name );
                array.push( parameters.defines[ name ] );

            }

        }

        if ( parameters.isRawShaderMaterial === false ) {

            getProgramCacheKeyParameters( array, parameters );
            getProgramCacheKeyBooleans( array, parameters );
            array.push( renderer.outputColorSpace );

        }

        array.push( parameters.customProgramCacheKey );

        return array.join();

    }

getProgramCacheKeyParameters(array: any, parameters: any): void

Parameters:

  • array any
  • parameters any

Returns: void

Calls:

  • array.push
Code
function getProgramCacheKeyParameters( array, parameters ) {

        array.push( parameters.precision );
        array.push( parameters.outputColorSpace );
        array.push( parameters.envMapMode );
        array.push( parameters.envMapCubeUVHeight );
        array.push( parameters.mapUv );
        array.push( parameters.alphaMapUv );
        array.push( parameters.lightMapUv );
        array.push( parameters.aoMapUv );
        array.push( parameters.bumpMapUv );
        array.push( parameters.normalMapUv );
        array.push( parameters.displacementMapUv );
        array.push( parameters.emissiveMapUv );
        array.push( parameters.metalnessMapUv );
        array.push( parameters.roughnessMapUv );
        array.push( parameters.anisotropyMapUv );
        array.push( parameters.clearcoatMapUv );
        array.push( parameters.clearcoatNormalMapUv );
        array.push( parameters.clearcoatRoughnessMapUv );
        array.push( parameters.iridescenceMapUv );
        array.push( parameters.iridescenceThicknessMapUv );
        array.push( parameters.sheenColorMapUv );
        array.push( parameters.sheenRoughnessMapUv );
        array.push( parameters.specularMapUv );
        array.push( parameters.specularColorMapUv );
        array.push( parameters.specularIntensityMapUv );
        array.push( parameters.transmissionMapUv );
        array.push( parameters.thicknessMapUv );
        array.push( parameters.combine );
        array.push( parameters.fogExp2 );
        array.push( parameters.sizeAttenuation );
        array.push( parameters.morphTargetsCount );
        array.push( parameters.morphAttributeCount );
        array.push( parameters.numDirLights );
        array.push( parameters.numPointLights );
        array.push( parameters.numSpotLights );
        array.push( parameters.numSpotLightMaps );
        array.push( parameters.numHemiLights );
        array.push( parameters.numRectAreaLights );
        array.push( parameters.numDirLightShadows );
        array.push( parameters.numPointLightShadows );
        array.push( parameters.numSpotLightShadows );
        array.push( parameters.numSpotLightShadowsWithMaps );
        array.push( parameters.numLightProbes );
        array.push( parameters.shadowMapType );
        array.push( parameters.toneMapping );
        array.push( parameters.numClippingPlanes );
        array.push( parameters.numClipIntersection );
        array.push( parameters.depthPacking );

    }

getProgramCacheKeyBooleans(array: any, parameters: any): void

Parameters:

  • array any
  • parameters any

Returns: void

Calls:

  • _programLayers.disableAll
  • _programLayers.enable
  • array.push
Code
function getProgramCacheKeyBooleans( array, parameters ) {

        _programLayers.disableAll();

        if ( parameters.supportsVertexTextures )
            _programLayers.enable( 0 );
        if ( parameters.instancing )
            _programLayers.enable( 1 );
        if ( parameters.instancingColor )
            _programLayers.enable( 2 );
        if ( parameters.instancingMorph )
            _programLayers.enable( 3 );
        if ( parameters.matcap )
            _programLayers.enable( 4 );
        if ( parameters.envMap )
            _programLayers.enable( 5 );
        if ( parameters.normalMapObjectSpace )
            _programLayers.enable( 6 );
        if ( parameters.normalMapTangentSpace )
            _programLayers.enable( 7 );
        if ( parameters.clearcoat )
            _programLayers.enable( 8 );
        if ( parameters.iridescence )
            _programLayers.enable( 9 );
        if ( parameters.alphaTest )
            _programLayers.enable( 10 );
        if ( parameters.vertexColors )
            _programLayers.enable( 11 );
        if ( parameters.vertexAlphas )
            _programLayers.enable( 12 );
        if ( parameters.vertexUv1s )
            _programLayers.enable( 13 );
        if ( parameters.vertexUv2s )
            _programLayers.enable( 14 );
        if ( parameters.vertexUv3s )
            _programLayers.enable( 15 );
        if ( parameters.vertexTangents )
            _programLayers.enable( 16 );
        if ( parameters.anisotropy )
            _programLayers.enable( 17 );
        if ( parameters.alphaHash )
            _programLayers.enable( 18 );
        if ( parameters.batching )
            _programLayers.enable( 19 );
        if ( parameters.dispersion )
            _programLayers.enable( 20 );
        if ( parameters.batchingColor )
            _programLayers.enable( 21 );
        if ( parameters.gradientMap )
            _programLayers.enable( 22 );

        array.push( _programLayers.mask );
        _programLayers.disableAll();

        if ( parameters.fog )
            _programLayers.enable( 0 );
        if ( parameters.useFog )
            _programLayers.enable( 1 );
        if ( parameters.flatShading )
            _programLayers.enable( 2 );
        if ( parameters.logarithmicDepthBuffer )
            _programLayers.enable( 3 );
        if ( parameters.reversedDepthBuffer )
            _programLayers.enable( 4 );
        if ( parameters.skinning )
            _programLayers.enable( 5 );
        if ( parameters.morphTargets )
            _programLayers.enable( 6 );
        if ( parameters.morphNormals )
            _programLayers.enable( 7 );
        if ( parameters.morphColors )
            _programLayers.enable( 8 );
        if ( parameters.premultipliedAlpha )
            _programLayers.enable( 9 );
        if ( parameters.shadowMapEnabled )
            _programLayers.enable( 10 );
        if ( parameters.doubleSided )
            _programLayers.enable( 11 );
        if ( parameters.flipSided )
            _programLayers.enable( 12 );
        if ( parameters.useDepthPacking )
            _programLayers.enable( 13 );
        if ( parameters.dithering )
            _programLayers.enable( 14 );
        if ( parameters.transmission )
            _programLayers.enable( 15 );
        if ( parameters.sheen )
            _programLayers.enable( 16 );
        if ( parameters.opaque )
            _programLayers.enable( 17 );
        if ( parameters.pointsUvs )
            _programLayers.enable( 18 );
        if ( parameters.decodeVideoTexture )
            _programLayers.enable( 19 );
        if ( parameters.decodeVideoTextureEmissive )
            _programLayers.enable( 20 );
        if ( parameters.alphaToCoverage )
            _programLayers.enable( 21 );

        array.push( _programLayers.mask );

    }

getUniforms(material: any): any

Parameters:

  • material any

Returns: any

Calls:

  • UniformsUtils.clone
Code
function getUniforms( material ) {

        const shaderID = shaderIDs[ material.type ];
        let uniforms;

        if ( shaderID ) {

            const shader = ShaderLib[ shaderID ];
            uniforms = UniformsUtils.clone( shader.uniforms );

        } else {

            uniforms = material.uniforms;

        }

        return uniforms;

    }

acquireProgram(parameters: any, cacheKey: any): any

Parameters:

  • parameters any
  • cacheKey any

Returns: any

Calls:

  • programs.push

Internal Comments:

// Check if code has been already compiled

Code
function acquireProgram( parameters, cacheKey ) {

        let program;

        // Check if code has been already compiled
        for ( let p = 0, pl = programs.length; p < pl; p ++ ) {

            const preexistingProgram = programs[ p ];

            if ( preexistingProgram.cacheKey === cacheKey ) {

                program = preexistingProgram;
                ++ program.usedTimes;

                break;

            }

        }

        if ( program === undefined ) {

            program = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );
            programs.push( program );

        }

        return program;

    }

releaseProgram(program: any): void

Parameters:

  • program any

Returns: void

Calls:

  • programs.indexOf
  • programs.pop
  • program.destroy

Internal Comments:

// Remove from unordered set (x2)
// Free WebGL resources (x4)

Code
function releaseProgram( program ) {

        if ( -- program.usedTimes === 0 ) {

            // Remove from unordered set
            const i = programs.indexOf( program );
            programs[ i ] = programs[ programs.length - 1 ];
            programs.pop();

            // Free WebGL resources
            program.destroy();

        }

    }

releaseShaderCache(material: any): void

Parameters:

  • material any

Returns: void

Calls:

  • _customShaders.remove
Code
function releaseShaderCache( material ) {

        _customShaders.remove( material );

    }

dispose(): void

Returns: void

Calls:

  • _customShaders.dispose
Code
function dispose() {

        _customShaders.dispose();

    }

WebGLProperties(): { has: (object: any) => boolean; get: (object: any) => any; remove: (object: any) => void; update: (object: any, key: any, value: any) => void; dispose: () => void; }

Returns: { has: (object: any) => boolean; get: (object: any) => any; remove: (object: any) => void; update: (object: any, key: any, value: any) => void; dispose: () => void; }

Calls:

  • properties.has
  • properties.get
  • properties.set
  • properties.delete
Code
function WebGLProperties() {

    let properties = new WeakMap();

    function has( object ) {

        return properties.has( object );

    }

    function get( object ) {

        let map = properties.get( object );

        if ( map === undefined ) {

            map = {};
            properties.set( object, map );

        }

        return map;

    }

    function remove( object ) {

        properties.delete( object );

    }

    function update( object, key, value ) {

        properties.get( object )[ key ] = value;

    }

    function dispose() {

        properties = new WeakMap();

    }

    return {
        has: has,
        get: get,
        remove: remove,
        update: update,
        dispose: dispose
    };

}

has(object: any): boolean

Parameters:

  • object any

Returns: boolean

Calls:

  • properties.has
Code
function has( object ) {

        return properties.has( object );

    }

get(object: any): any

Parameters:

  • object any

Returns: any

Calls:

  • properties.get
  • properties.set
Code
function get( object ) {

        let map = properties.get( object );

        if ( map === undefined ) {

            map = {};
            properties.set( object, map );

        }

        return map;

    }

remove(object: any): void

Parameters:

  • object any

Returns: void

Calls:

  • properties.delete
Code
function remove( object ) {

        properties.delete( object );

    }

update(object: any, key: any, value: any): void

Parameters:

  • object any
  • key any
  • value any

Returns: void

Calls:

  • properties.get
Code
function update( object, key, value ) {

        properties.get( object )[ key ] = value;

    }

dispose(): void

Returns: void

Code
function dispose() {

        properties = new WeakMap();

    }

painterSortStable(a: any, b: any): number

Parameters:

  • a any
  • b any

Returns: number

Code
function painterSortStable( a, b ) {

    if ( a.groupOrder !== b.groupOrder ) {

        return a.groupOrder - b.groupOrder;

    } else if ( a.renderOrder !== b.renderOrder ) {

        return a.renderOrder - b.renderOrder;

    } else if ( a.material.id !== b.material.id ) {

        return a.material.id - b.material.id;

    } else if ( a.z !== b.z ) {

        return a.z - b.z;

    } else {

        return a.id - b.id;

    }

}

reversePainterSortStable(a: any, b: any): number

Parameters:

  • a any
  • b any

Returns: number

Code
function reversePainterSortStable( a, b ) {

    if ( a.groupOrder !== b.groupOrder ) {

        return a.groupOrder - b.groupOrder;

    } else if ( a.renderOrder !== b.renderOrder ) {

        return a.renderOrder - b.renderOrder;

    } else if ( a.z !== b.z ) {

        return b.z - a.z;

    } else {

        return a.id - b.id;

    }

}

WebGLRenderList(): { opaque: any[]; transmissive: any[]; transparent: any[]; init: () => void; push: (object: any, geometry: any, material: any, groupOrder: any, z: any, group: any) => void; unshift: (object: any, geometry: any, material: any, groupOrder: any, z: any, group: any) => void; finish: () => void; sort: (customOpaqueSort: a...

Returns: { opaque: any[]; transmissive: any[]; transparent: any[]; init: () => void; push: (object: any, geometry: any, material: any, groupOrder: any, z: any, group: any) => void; unshift: (object: any, geometry: any, material: any, groupOrder: any, z: any, group: any) => void; finish: () => void; sort: (customOpaqueSort: a...

Calls:

  • getNextRenderItem
  • transmissive.push
  • transparent.push
  • opaque.push
  • transmissive.unshift
  • transparent.unshift
  • opaque.unshift
  • opaque.sort
  • transmissive.sort
  • transparent.sort

Internal Comments:

// Clear references from inactive renderItems in the list

Code
function WebGLRenderList() {

    const renderItems = [];
    let renderItemsIndex = 0;

    const opaque = [];
    const transmissive = [];
    const transparent = [];

    function init() {

        renderItemsIndex = 0;

        opaque.length = 0;
        transmissive.length = 0;
        transparent.length = 0;

    }

    function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {

        let renderItem = renderItems[ renderItemsIndex ];

        if ( renderItem === undefined ) {

            renderItem = {
                id: object.id,
                object: object,
                geometry: geometry,
                material: material,
                groupOrder: groupOrder,
                renderOrder: object.renderOrder,
                z: z,
                group: group
            };

            renderItems[ renderItemsIndex ] = renderItem;

        } else {

            renderItem.id = object.id;
            renderItem.object = object;
            renderItem.geometry = geometry;
            renderItem.material = material;
            renderItem.groupOrder = groupOrder;
            renderItem.renderOrder = object.renderOrder;
            renderItem.z = z;
            renderItem.group = group;

        }

        renderItemsIndex ++;

        return renderItem;

    }

    function push( object, geometry, material, groupOrder, z, group ) {

        const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );

        if ( material.transmission > 0.0 ) {

            transmissive.push( renderItem );

        } else if ( material.transparent === true ) {

            transparent.push( renderItem );

        } else {

            opaque.push( renderItem );

        }

    }

    function unshift( object, geometry, material, groupOrder, z, group ) {

        const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );

        if ( material.transmission > 0.0 ) {

            transmissive.unshift( renderItem );

        } else if ( material.transparent === true ) {

            transparent.unshift( renderItem );

        } else {

            opaque.unshift( renderItem );

        }

    }

    function sort( customOpaqueSort, customTransparentSort ) {

        if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
        if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
        if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );

    }

    function finish() {

        // Clear references from inactive renderItems in the list

        for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {

            const renderItem = renderItems[ i ];

            if ( renderItem.id === null ) break;

            renderItem.id = null;
            renderItem.object = null;
            renderItem.geometry = null;
            renderItem.material = null;
            renderItem.group = null;

        }

    }

    return {

        opaque: opaque,
        transmissive: transmissive,
        transparent: transparent,

        init: init,
        push: push,
        unshift: unshift,
        finish: finish,

        sort: sort
    };

}

init(): void

Returns: void

Code
function init() {

        renderItemsIndex = 0;

        opaque.length = 0;
        transmissive.length = 0;
        transparent.length = 0;

    }

getNextRenderItem(object: any, geometry: any, material: any, groupOrder: any, z: any, group: any): any

Parameters:

  • object any
  • geometry any
  • material any
  • groupOrder any
  • z any
  • group any

Returns: any

Code
function getNextRenderItem( object, geometry, material, groupOrder, z, group ) {

        let renderItem = renderItems[ renderItemsIndex ];

        if ( renderItem === undefined ) {

            renderItem = {
                id: object.id,
                object: object,
                geometry: geometry,
                material: material,
                groupOrder: groupOrder,
                renderOrder: object.renderOrder,
                z: z,
                group: group
            };

            renderItems[ renderItemsIndex ] = renderItem;

        } else {

            renderItem.id = object.id;
            renderItem.object = object;
            renderItem.geometry = geometry;
            renderItem.material = material;
            renderItem.groupOrder = groupOrder;
            renderItem.renderOrder = object.renderOrder;
            renderItem.z = z;
            renderItem.group = group;

        }

        renderItemsIndex ++;

        return renderItem;

    }

push(object: any, geometry: any, material: any, groupOrder: any, z: any, group: any): void

Parameters:

  • object any
  • geometry any
  • material any
  • groupOrder any
  • z any
  • group any

Returns: void

Calls:

  • getNextRenderItem
  • transmissive.push
  • transparent.push
  • opaque.push
Code
function push( object, geometry, material, groupOrder, z, group ) {

        const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );

        if ( material.transmission > 0.0 ) {

            transmissive.push( renderItem );

        } else if ( material.transparent === true ) {

            transparent.push( renderItem );

        } else {

            opaque.push( renderItem );

        }

    }

unshift(object: any, geometry: any, material: any, groupOrder: any, z: any, group: any): void

Parameters:

  • object any
  • geometry any
  • material any
  • groupOrder any
  • z any
  • group any

Returns: void

Calls:

  • getNextRenderItem
  • transmissive.unshift
  • transparent.unshift
  • opaque.unshift
Code
function unshift( object, geometry, material, groupOrder, z, group ) {

        const renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );

        if ( material.transmission > 0.0 ) {

            transmissive.unshift( renderItem );

        } else if ( material.transparent === true ) {

            transparent.unshift( renderItem );

        } else {

            opaque.unshift( renderItem );

        }

    }

sort(customOpaqueSort: any, customTransparentSort: any): void

Parameters:

  • customOpaqueSort any
  • customTransparentSort any

Returns: void

Calls:

  • opaque.sort
  • transmissive.sort
  • transparent.sort
Code
function sort( customOpaqueSort, customTransparentSort ) {

        if ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );
        if ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );
        if ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );

    }

finish(): void

Returns: void

Internal Comments:

// Clear references from inactive renderItems in the list

Code
function finish() {

        // Clear references from inactive renderItems in the list

        for ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {

            const renderItem = renderItems[ i ];

            if ( renderItem.id === null ) break;

            renderItem.id = null;
            renderItem.object = null;
            renderItem.geometry = null;
            renderItem.material = null;
            renderItem.group = null;

        }

    }

WebGLRenderLists(): { get: (scene: any, renderCallDepth: any) => any; dispose: () => void; }

Returns: { get: (scene: any, renderCallDepth: any) => any; dispose: () => void; }

Calls:

  • lists.get
  • lists.set
  • listArray.push
Code
function WebGLRenderLists() {

    let lists = new WeakMap();

    function get( scene, renderCallDepth ) {

        const listArray = lists.get( scene );
        let list;

        if ( listArray === undefined ) {

            list = new WebGLRenderList();
            lists.set( scene, [ list ] );

        } else {

            if ( renderCallDepth >= listArray.length ) {

                list = new WebGLRenderList();
                listArray.push( list );

            } else {

                list = listArray[ renderCallDepth ];

            }

        }

        return list;

    }

    function dispose() {

        lists = new WeakMap();

    }

    return {
        get: get,
        dispose: dispose
    };

}

get(scene: any, renderCallDepth: any): any

Parameters:

  • scene any
  • renderCallDepth any

Returns: any

Calls:

  • lists.get
  • lists.set
  • listArray.push
Code
function get( scene, renderCallDepth ) {

        const listArray = lists.get( scene );
        let list;

        if ( listArray === undefined ) {

            list = new WebGLRenderList();
            lists.set( scene, [ list ] );

        } else {

            if ( renderCallDepth >= listArray.length ) {

                list = new WebGLRenderList();
                listArray.push( list );

            } else {

                list = listArray[ renderCallDepth ];

            }

        }

        return list;

    }

dispose(): void

Returns: void

Code
function dispose() {

        lists = new WeakMap();

    }

UniformsCache(): { get: (light: any) => any; }

Returns: { get: (light: any) => any; }

Code
function UniformsCache() {

    const lights = {};

    return {

        get: function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

    };

}

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        direction: new Vector3(),
                        color: new Color()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        position: new Vector3(),
                        direction: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        coneCos: 0,
                        penumbraCos: 0,
                        decay: 0
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        position: new Vector3(),
                        color: new Color(),
                        distance: 0,
                        decay: 0
                    };
                    break;

                case 'HemisphereLight':
                    uniforms = {
                        direction: new Vector3(),
                        skyColor: new Color(),
                        groundColor: new Color()
                    };
                    break;

                case 'RectAreaLight':
                    uniforms = {
                        color: new Color(),
                        position: new Vector3(),
                        halfWidth: new Vector3(),
                        halfHeight: new Vector3()
                    };
                    break;

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

ShadowUniformsCache(): { get: (light: any) => any; }

Returns: { get: (light: any) => any; }

Code
function ShadowUniformsCache() {

    const lights = {};

    return {

        get: function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

    };

}

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

get(light: any): any

Parameters:

  • light any

Returns: any

Code
function ( light ) {

            if ( lights[ light.id ] !== undefined ) {

                return lights[ light.id ];

            }

            let uniforms;

            switch ( light.type ) {

                case 'DirectionalLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'SpotLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2()
                    };
                    break;

                case 'PointLight':
                    uniforms = {
                        shadowIntensity: 1,
                        shadowBias: 0,
                        shadowNormalBias: 0,
                        shadowRadius: 1,
                        shadowMapSize: new Vector2(),
                        shadowCameraNear: 1,
                        shadowCameraFar: 1000
                    };
                    break;

                // TODO (abelnation): set RectAreaLight shadow uniforms

            }

            lights[ light.id ] = uniforms;

            return uniforms;

        }

shadowCastingAndTexturingLightsFirst(lightA: any, lightB: any): number

Parameters:

  • lightA any
  • lightB any

Returns: number

Code
function shadowCastingAndTexturingLightsFirst( lightA, lightB ) {

    return ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );

}

WebGLLights(extensions: any): { setup: (lights: any) => void; setupView: (lights: any, camera: any) => void; state: { version: number; hash: { directionalLength: number; pointLength: number; spotLength: number; rectAreaLength: number; ... 5 more ...; numLightProbes: number; }; ... 20 more ...; numLightProbes: number; }; }

Parameters:

  • extensions any

Returns: { setup: (lights: any) => void; setupView: (lights: any, camera: any) => void; state: { version: number; hash: { directionalLength: number; pointLength: number; spotLength: number; rectAreaLength: number; ... 5 more ...; numLightProbes: number; }; ... 20 more ...; numLightProbes: number; }; }

Calls:

  • ShadowUniformsCache
  • state.probe.push
  • state.probe[ i ].set
  • lights.sort
  • state.probe[ j ].addScaledVector
  • cache.get
  • uniforms.color.copy( light.color ).multiplyScalar
  • shadowCache.get
  • uniforms.position.setFromMatrixPosition
  • uniforms.color.copy( color ).multiplyScalar
  • Math.cos
  • shadow.updateMatrices
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.skyColor.copy( light.color ).multiplyScalar
  • uniforms.groundColor.copy( light.groundColor ).multiplyScalar
  • extensions.has
  • uniforms.direction.setFromMatrixPosition
  • vector3.setFromMatrixPosition
  • uniforms.direction.sub
  • uniforms.direction.transformDirection
  • uniforms.position.applyMatrix4
  • matrix42.identity
  • matrix4.copy
  • matrix4.premultiply
  • matrix42.extractRotation
  • uniforms.halfWidth.applyMatrix4
  • uniforms.halfHeight.applyMatrix4

Internal Comments:

// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] (x4)
// make sure the lightMatrix is up to date (x4)
// TODO : do it if required only (x4)
// extract local rotation of light to derive width/height half vectors (x4)

Code
function WebGLLights( extensions ) {

    const cache = new UniformsCache();

    const shadowCache = ShadowUniformsCache();

    const state = {

        version: 0,

        hash: {
            directionalLength: -1,
            pointLength: -1,
            spotLength: -1,
            rectAreaLength: -1,
            hemiLength: -1,

            numDirectionalShadows: -1,
            numPointShadows: -1,
            numSpotShadows: -1,
            numSpotMaps: -1,

            numLightProbes: -1
        },

        ambient: [ 0, 0, 0 ],
        probe: [],
        directional: [],
        directionalShadow: [],
        directionalShadowMap: [],
        directionalShadowMatrix: [],
        spot: [],
        spotLightMap: [],
        spotShadow: [],
        spotShadowMap: [],
        spotLightMatrix: [],
        rectArea: [],
        rectAreaLTC1: null,
        rectAreaLTC2: null,
        point: [],
        pointShadow: [],
        pointShadowMap: [],
        pointShadowMatrix: [],
        hemi: [],
        numSpotLightShadowsWithMaps: 0,
        numLightProbes: 0

    };

    for ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );

    const vector3 = new Vector3();
    const matrix4 = new Matrix4();
    const matrix42 = new Matrix4();

    function setup( lights ) {

        let r = 0, g = 0, b = 0;

        for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        let numDirectionalShadows = 0;
        let numPointShadows = 0;
        let numSpotShadows = 0;
        let numSpotMaps = 0;
        let numSpotShadowsWithMaps = 0;

        let numLightProbes = 0;

        // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
        lights.sort( shadowCastingAndTexturingLightsFirst );

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            const color = light.color;
            const intensity = light.intensity;
            const distance = light.distance;

            const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;

            if ( light.isAmbientLight ) {

                r += color.r * intensity;
                g += color.g * intensity;
                b += color.b * intensity;

            } else if ( light.isLightProbe ) {

                for ( let j = 0; j < 9; j ++ ) {

                    state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );

                }

                numLightProbes ++;

            } else if ( light.isDirectionalLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.directionalShadow[ directionalLength ] = shadowUniforms;
                    state.directionalShadowMap[ directionalLength ] = shadowMap;
                    state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;

                    numDirectionalShadows ++;

                }

                state.directional[ directionalLength ] = uniforms;

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = cache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );

                uniforms.color.copy( color ).multiplyScalar( intensity );
                uniforms.distance = distance;

                uniforms.coneCos = Math.cos( light.angle );
                uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
                uniforms.decay = light.decay;

                state.spot[ spotLength ] = uniforms;

                const shadow = light.shadow;

                if ( light.map ) {

                    state.spotLightMap[ numSpotMaps ] = light.map;
                    numSpotMaps ++;

                    // make sure the lightMatrix is up to date
                    // TODO : do it if required only
                    shadow.updateMatrices( light );

                    if ( light.castShadow ) numSpotShadowsWithMaps ++;

                }

                state.spotLightMatrix[ spotLength ] = shadow.matrix;

                if ( light.castShadow ) {

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.spotShadow[ spotLength ] = shadowUniforms;
                    state.spotShadowMap[ spotLength ] = shadowMap;

                    numSpotShadows ++;

                }

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( color ).multiplyScalar( intensity );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                state.rectArea[ rectAreaLength ] = uniforms;

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.distance = light.distance;
                uniforms.decay = light.decay;

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;
                    shadowUniforms.shadowCameraNear = shadow.camera.near;
                    shadowUniforms.shadowCameraFar = shadow.camera.far;

                    state.pointShadow[ pointLength ] = shadowUniforms;
                    state.pointShadowMap[ pointLength ] = shadowMap;
                    state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;

                    numPointShadows ++;

                }

                state.point[ pointLength ] = uniforms;

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = cache.get( light );

                uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
                uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );

                state.hemi[ hemiLength ] = uniforms;

                hemiLength ++;

            }

        }

        if ( rectAreaLength > 0 ) {

            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;

            }

        }

        state.ambient[ 0 ] = r;
        state.ambient[ 1 ] = g;
        state.ambient[ 2 ] = b;

        const hash = state.hash;

        if ( hash.directionalLength !== directionalLength ||
            hash.pointLength !== pointLength ||
            hash.spotLength !== spotLength ||
            hash.rectAreaLength !== rectAreaLength ||
            hash.hemiLength !== hemiLength ||
            hash.numDirectionalShadows !== numDirectionalShadows ||
            hash.numPointShadows !== numPointShadows ||
            hash.numSpotShadows !== numSpotShadows ||
            hash.numSpotMaps !== numSpotMaps ||
            hash.numLightProbes !== numLightProbes ) {

            state.directional.length = directionalLength;
            state.spot.length = spotLength;
            state.rectArea.length = rectAreaLength;
            state.point.length = pointLength;
            state.hemi.length = hemiLength;

            state.directionalShadow.length = numDirectionalShadows;
            state.directionalShadowMap.length = numDirectionalShadows;
            state.pointShadow.length = numPointShadows;
            state.pointShadowMap.length = numPointShadows;
            state.spotShadow.length = numSpotShadows;
            state.spotShadowMap.length = numSpotShadows;
            state.directionalShadowMatrix.length = numDirectionalShadows;
            state.pointShadowMatrix.length = numPointShadows;
            state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
            state.spotLightMap.length = numSpotMaps;
            state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
            state.numLightProbes = numLightProbes;

            hash.directionalLength = directionalLength;
            hash.pointLength = pointLength;
            hash.spotLength = spotLength;
            hash.rectAreaLength = rectAreaLength;
            hash.hemiLength = hemiLength;

            hash.numDirectionalShadows = numDirectionalShadows;
            hash.numPointShadows = numPointShadows;
            hash.numSpotShadows = numSpotShadows;
            hash.numSpotMaps = numSpotMaps;

            hash.numLightProbes = numLightProbes;

            state.version = nextVersion ++;

        }

    }

    function setupView( lights, camera ) {

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        const viewMatrix = camera.matrixWorldInverse;

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            if ( light.isDirectionalLight ) {

                const uniforms = state.directional[ directionalLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = state.spot[ spotLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = state.rectArea[ rectAreaLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                // extract local rotation of light to derive width/height half vectors
                matrix42.identity();
                matrix4.copy( light.matrixWorld );
                matrix4.premultiply( viewMatrix );
                matrix42.extractRotation( matrix4 );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                uniforms.halfWidth.applyMatrix4( matrix42 );
                uniforms.halfHeight.applyMatrix4( matrix42 );

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = state.point[ pointLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = state.hemi[ hemiLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                uniforms.direction.transformDirection( viewMatrix );

                hemiLength ++;

            }

        }

    }

    return {
        setup: setup,
        setupView: setupView,
        state: state
    };

}

setup(lights: any): void

Parameters:

  • lights any

Returns: void

Calls:

  • state.probe[ i ].set
  • lights.sort
  • state.probe[ j ].addScaledVector
  • cache.get
  • uniforms.color.copy( light.color ).multiplyScalar
  • shadowCache.get
  • uniforms.position.setFromMatrixPosition
  • uniforms.color.copy( color ).multiplyScalar
  • Math.cos
  • shadow.updateMatrices
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.skyColor.copy( light.color ).multiplyScalar
  • uniforms.groundColor.copy( light.groundColor ).multiplyScalar
  • extensions.has

Internal Comments:

// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ] (x4)
// make sure the lightMatrix is up to date (x4)
// TODO : do it if required only (x4)

Code
function setup( lights ) {

        let r = 0, g = 0, b = 0;

        for ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        let numDirectionalShadows = 0;
        let numPointShadows = 0;
        let numSpotShadows = 0;
        let numSpotMaps = 0;
        let numSpotShadowsWithMaps = 0;

        let numLightProbes = 0;

        // ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]
        lights.sort( shadowCastingAndTexturingLightsFirst );

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            const color = light.color;
            const intensity = light.intensity;
            const distance = light.distance;

            const shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;

            if ( light.isAmbientLight ) {

                r += color.r * intensity;
                g += color.g * intensity;
                b += color.b * intensity;

            } else if ( light.isLightProbe ) {

                for ( let j = 0; j < 9; j ++ ) {

                    state.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );

                }

                numLightProbes ++;

            } else if ( light.isDirectionalLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.directionalShadow[ directionalLength ] = shadowUniforms;
                    state.directionalShadowMap[ directionalLength ] = shadowMap;
                    state.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;

                    numDirectionalShadows ++;

                }

                state.directional[ directionalLength ] = uniforms;

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = cache.get( light );

                uniforms.position.setFromMatrixPosition( light.matrixWorld );

                uniforms.color.copy( color ).multiplyScalar( intensity );
                uniforms.distance = distance;

                uniforms.coneCos = Math.cos( light.angle );
                uniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );
                uniforms.decay = light.decay;

                state.spot[ spotLength ] = uniforms;

                const shadow = light.shadow;

                if ( light.map ) {

                    state.spotLightMap[ numSpotMaps ] = light.map;
                    numSpotMaps ++;

                    // make sure the lightMatrix is up to date
                    // TODO : do it if required only
                    shadow.updateMatrices( light );

                    if ( light.castShadow ) numSpotShadowsWithMaps ++;

                }

                state.spotLightMatrix[ spotLength ] = shadow.matrix;

                if ( light.castShadow ) {

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;

                    state.spotShadow[ spotLength ] = shadowUniforms;
                    state.spotShadowMap[ spotLength ] = shadowMap;

                    numSpotShadows ++;

                }

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( color ).multiplyScalar( intensity );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                state.rectArea[ rectAreaLength ] = uniforms;

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = cache.get( light );

                uniforms.color.copy( light.color ).multiplyScalar( light.intensity );
                uniforms.distance = light.distance;
                uniforms.decay = light.decay;

                if ( light.castShadow ) {

                    const shadow = light.shadow;

                    const shadowUniforms = shadowCache.get( light );

                    shadowUniforms.shadowIntensity = shadow.intensity;
                    shadowUniforms.shadowBias = shadow.bias;
                    shadowUniforms.shadowNormalBias = shadow.normalBias;
                    shadowUniforms.shadowRadius = shadow.radius;
                    shadowUniforms.shadowMapSize = shadow.mapSize;
                    shadowUniforms.shadowCameraNear = shadow.camera.near;
                    shadowUniforms.shadowCameraFar = shadow.camera.far;

                    state.pointShadow[ pointLength ] = shadowUniforms;
                    state.pointShadowMap[ pointLength ] = shadowMap;
                    state.pointShadowMatrix[ pointLength ] = light.shadow.matrix;

                    numPointShadows ++;

                }

                state.point[ pointLength ] = uniforms;

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = cache.get( light );

                uniforms.skyColor.copy( light.color ).multiplyScalar( intensity );
                uniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );

                state.hemi[ hemiLength ] = uniforms;

                hemiLength ++;

            }

        }

        if ( rectAreaLength > 0 ) {

            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;

            }

        }

        state.ambient[ 0 ] = r;
        state.ambient[ 1 ] = g;
        state.ambient[ 2 ] = b;

        const hash = state.hash;

        if ( hash.directionalLength !== directionalLength ||
            hash.pointLength !== pointLength ||
            hash.spotLength !== spotLength ||
            hash.rectAreaLength !== rectAreaLength ||
            hash.hemiLength !== hemiLength ||
            hash.numDirectionalShadows !== numDirectionalShadows ||
            hash.numPointShadows !== numPointShadows ||
            hash.numSpotShadows !== numSpotShadows ||
            hash.numSpotMaps !== numSpotMaps ||
            hash.numLightProbes !== numLightProbes ) {

            state.directional.length = directionalLength;
            state.spot.length = spotLength;
            state.rectArea.length = rectAreaLength;
            state.point.length = pointLength;
            state.hemi.length = hemiLength;

            state.directionalShadow.length = numDirectionalShadows;
            state.directionalShadowMap.length = numDirectionalShadows;
            state.pointShadow.length = numPointShadows;
            state.pointShadowMap.length = numPointShadows;
            state.spotShadow.length = numSpotShadows;
            state.spotShadowMap.length = numSpotShadows;
            state.directionalShadowMatrix.length = numDirectionalShadows;
            state.pointShadowMatrix.length = numPointShadows;
            state.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;
            state.spotLightMap.length = numSpotMaps;
            state.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;
            state.numLightProbes = numLightProbes;

            hash.directionalLength = directionalLength;
            hash.pointLength = pointLength;
            hash.spotLength = spotLength;
            hash.rectAreaLength = rectAreaLength;
            hash.hemiLength = hemiLength;

            hash.numDirectionalShadows = numDirectionalShadows;
            hash.numPointShadows = numPointShadows;
            hash.numSpotShadows = numSpotShadows;
            hash.numSpotMaps = numSpotMaps;

            hash.numLightProbes = numLightProbes;

            state.version = nextVersion ++;

        }

    }

setupView(lights: any, camera: any): void

Parameters:

  • lights any
  • camera any

Returns: void

Calls:

  • uniforms.direction.setFromMatrixPosition
  • vector3.setFromMatrixPosition
  • uniforms.direction.sub
  • uniforms.direction.transformDirection
  • uniforms.position.setFromMatrixPosition
  • uniforms.position.applyMatrix4
  • matrix42.identity
  • matrix4.copy
  • matrix4.premultiply
  • matrix42.extractRotation
  • uniforms.halfWidth.set
  • uniforms.halfHeight.set
  • uniforms.halfWidth.applyMatrix4
  • uniforms.halfHeight.applyMatrix4

Internal Comments:

// extract local rotation of light to derive width/height half vectors (x4)

Code
function setupView( lights, camera ) {

        let directionalLength = 0;
        let pointLength = 0;
        let spotLength = 0;
        let rectAreaLength = 0;
        let hemiLength = 0;

        const viewMatrix = camera.matrixWorldInverse;

        for ( let i = 0, l = lights.length; i < l; i ++ ) {

            const light = lights[ i ];

            if ( light.isDirectionalLight ) {

                const uniforms = state.directional[ directionalLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                directionalLength ++;

            } else if ( light.isSpotLight ) {

                const uniforms = state.spot[ spotLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                vector3.setFromMatrixPosition( light.target.matrixWorld );
                uniforms.direction.sub( vector3 );
                uniforms.direction.transformDirection( viewMatrix );

                spotLength ++;

            } else if ( light.isRectAreaLight ) {

                const uniforms = state.rectArea[ rectAreaLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                // extract local rotation of light to derive width/height half vectors
                matrix42.identity();
                matrix4.copy( light.matrixWorld );
                matrix4.premultiply( viewMatrix );
                matrix42.extractRotation( matrix4 );

                uniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );
                uniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );

                uniforms.halfWidth.applyMatrix4( matrix42 );
                uniforms.halfHeight.applyMatrix4( matrix42 );

                rectAreaLength ++;

            } else if ( light.isPointLight ) {

                const uniforms = state.point[ pointLength ];

                uniforms.position.setFromMatrixPosition( light.matrixWorld );
                uniforms.position.applyMatrix4( viewMatrix );

                pointLength ++;

            } else if ( light.isHemisphereLight ) {

                const uniforms = state.hemi[ hemiLength ];

                uniforms.direction.setFromMatrixPosition( light.matrixWorld );
                uniforms.direction.transformDirection( viewMatrix );

                hemiLength ++;

            }

        }

    }

WebGLRenderState(extensions: any): { init: (camera: any) => void; state: { lightsArray: any[]; shadowsArray: any[]; camera: any; lights: any; transmissionRenderTarget: {}; }; setupLights: () => void; setupLightsView: (camera: any) => void; pushLight: (light: any) => void; pushShadow: (shadowLight: any) => void; }

Parameters:

  • extensions any

Returns: { init: (camera: any) => void; state: { lightsArray: any[]; shadowsArray: any[]; camera: any; lights: any; transmissionRenderTarget: {}; }; setupLights: () => void; setupLightsView: (camera: any) => void; pushLight: (light: any) => void; pushShadow: (shadowLight: any) => void; }

Calls:

  • lightsArray.push
  • shadowsArray.push
  • lights.setup
  • lights.setupView
Code
function WebGLRenderState( extensions ) {

    const lights = new WebGLLights( extensions );

    const lightsArray = [];
    const shadowsArray = [];

    function init( camera ) {

        state.camera = camera;

        lightsArray.length = 0;
        shadowsArray.length = 0;

    }

    function pushLight( light ) {

        lightsArray.push( light );

    }

    function pushShadow( shadowLight ) {

        shadowsArray.push( shadowLight );

    }

    function setupLights() {

        lights.setup( lightsArray );

    }

    function setupLightsView( camera ) {

        lights.setupView( lightsArray, camera );

    }

    const state = {
        lightsArray: lightsArray,
        shadowsArray: shadowsArray,

        camera: null,

        lights: lights,

        transmissionRenderTarget: {}
    };

    return {
        init: init,
        state: state,
        setupLights: setupLights,
        setupLightsView: setupLightsView,

        pushLight: pushLight,
        pushShadow: pushShadow
    };

}

init(camera: any): void

Parameters:

  • camera any

Returns: void

Code
function init( camera ) {

        state.camera = camera;

        lightsArray.length = 0;
        shadowsArray.length = 0;

    }

pushLight(light: any): void

Parameters:

  • light any

Returns: void

Calls:

  • lightsArray.push
Code
function pushLight( light ) {

        lightsArray.push( light );

    }

pushShadow(shadowLight: any): void

Parameters:

  • shadowLight any

Returns: void

Calls:

  • shadowsArray.push
Code
function pushShadow( shadowLight ) {

        shadowsArray.push( shadowLight );

    }

setupLights(): void

Returns: void

Calls:

  • lights.setup
Code
function setupLights() {

        lights.setup( lightsArray );

    }

setupLightsView(camera: any): void

Parameters:

  • camera any

Returns: void

Calls:

  • lights.setupView
Code
function setupLightsView( camera ) {

        lights.setupView( lightsArray, camera );

    }

WebGLRenderStates(extensions: any): { get: (scene: any, renderCallDepth?: number) => any; dispose: () => void; }

Parameters:

  • extensions any

Returns: { get: (scene: any, renderCallDepth?: number) => any; dispose: () => void; }

Calls:

  • renderStates.get
  • renderStates.set
  • renderStateArray.push
Code
function WebGLRenderStates( extensions ) {

    let renderStates = new WeakMap();

    function get( scene, renderCallDepth = 0 ) {

        const renderStateArray = renderStates.get( scene );
        let renderState;

        if ( renderStateArray === undefined ) {

            renderState = new WebGLRenderState( extensions );
            renderStates.set( scene, [ renderState ] );

        } else {

            if ( renderCallDepth >= renderStateArray.length ) {

                renderState = new WebGLRenderState( extensions );
                renderStateArray.push( renderState );

            } else {

                renderState = renderStateArray[ renderCallDepth ];

            }

        }

        return renderState;

    }

    function dispose() {

        renderStates = new WeakMap();

    }

    return {
        get: get,
        dispose: dispose
    };

}

get(scene: any, renderCallDepth: number): any

Parameters:

  • scene any
  • renderCallDepth number

Returns: any

Calls:

  • renderStates.get
  • renderStates.set
  • renderStateArray.push
Code
function get( scene, renderCallDepth = 0 ) {

        const renderStateArray = renderStates.get( scene );
        let renderState;

        if ( renderStateArray === undefined ) {

            renderState = new WebGLRenderState( extensions );
            renderStates.set( scene, [ renderState ] );

        } else {

            if ( renderCallDepth >= renderStateArray.length ) {

                renderState = new WebGLRenderState( extensions );
                renderStateArray.push( renderState );

            } else {

                renderState = renderStateArray[ renderCallDepth ];

            }

        }

        return renderState;

    }

dispose(): void

Returns: void

Code
function dispose() {

        renderStates = new WeakMap();

    }

WebGLShadowMap(renderer: any, objects: any, capabilities: any): void

Parameters:

  • renderer any
  • objects any
  • capabilities any

Returns: void

Calls:

  • shadowMaterialVertical.clone
  • fullScreenTri.setAttribute
  • renderer.getRenderTarget
  • renderer.getActiveCubeFace
  • renderer.getActiveMipmapLevel
  • _state.setBlending
  • _state.buffers.depth.getReversed
  • _state.buffers.color.setClear
  • _state.buffers.depth.setTest
  • _state.setScissorTest
  • console.warn
  • _shadowMapSize.copy
  • shadow.getFrameExtents
  • _shadowMapSize.multiply
  • _viewportSize.copy
  • Math.floor
  • shadow.map.dispose
  • shadow.camera.updateProjectionMatrix
  • renderer.setRenderTarget
  • renderer.clear
  • shadow.getViewportCount
  • shadow.getViewport
  • _viewport.set
  • _state.viewport
  • shadow.updateMatrices
  • shadow.getFrustum
  • renderObject
  • VSMPass
  • objects.update
  • renderer.renderBufferDirect
  • Array.isArray
  • result.clone
  • material.addEventListener
  • renderer.properties.get
  • object.layers.test
  • _frustum.intersectsObject
  • object.modelViewMatrix.multiplyMatrices
  • getDepthMaterial
  • object.onBeforeShadow
  • object.onAfterShadow
  • material.removeEventListener
  • shadowMaterial.dispose

Internal Comments:

// Set GL state for depth map. (x4)
// check for shadow map type changes (x2)
// render depth map
// do blur pass for VSM
// vertical pass (x6)
// horizontal pass (x6)
// in this case we need a unique material instance reflecting the (x2)
// appropriate state (x2)
// make sure to remove the unique distance/depth materials used for shadow map rendering

Code
function WebGLShadowMap( renderer, objects, capabilities ) {

    let _frustum = new Frustum();

    const _shadowMapSize = new Vector2(),
        _viewportSize = new Vector2(),

        _viewport = new Vector4(),

        _depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),
        _distanceMaterial = new MeshDistanceMaterial(),

        _materialCache = {},

        _maxTextureSize = capabilities.maxTextureSize;

    const shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide };

    const shadowMaterialVertical = new ShaderMaterial( {
        defines: {
            VSM_SAMPLES: 8
        },
        uniforms: {
            shadow_pass: { value: null },
            resolution: { value: new Vector2() },
            radius: { value: 4.0 }
        },

        vertexShader: vertex,
        fragmentShader: fragment

    } );

    const shadowMaterialHorizontal = shadowMaterialVertical.clone();
    shadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;

    const fullScreenTri = new BufferGeometry();
    fullScreenTri.setAttribute(
        'position',
        new BufferAttribute(
            new Float32Array( [ -1, -1, 0.5, 3, -1, 0.5, -1, 3, 0.5 ] ),
            3
        )
    );

    const fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );

    const scope = this;

    this.enabled = false;

    this.autoUpdate = true;
    this.needsUpdate = false;

    this.type = PCFShadowMap;
    let _previousType = this.type;

    this.render = function ( lights, scene, camera ) {

        if ( scope.enabled === false ) return;
        if ( scope.autoUpdate === false && scope.needsUpdate === false ) return;

        if ( lights.length === 0 ) return;

        const currentRenderTarget = renderer.getRenderTarget();
        const activeCubeFace = renderer.getActiveCubeFace();
        const activeMipmapLevel = renderer.getActiveMipmapLevel();

        const _state = renderer.state;

        // Set GL state for depth map.
        _state.setBlending( NoBlending );

        if ( _state.buffers.depth.getReversed() === true ) {

            _state.buffers.color.setClear( 0, 0, 0, 0 );

        } else {

            _state.buffers.color.setClear( 1, 1, 1, 1 );

        }

        _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 ++ ) {

            const light = lights[ i ];
            const shadow = light.shadow;

            if ( shadow === undefined ) {

                console.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );
                continue;

            }

            if ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;

            _shadowMapSize.copy( shadow.mapSize );

            const shadowFrameExtents = shadow.getFrameExtents();

            _shadowMapSize.multiply( shadowFrameExtents );

            _viewportSize.copy( shadow.mapSize );

            if ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {

                if ( _shadowMapSize.x > _maxTextureSize ) {

                    _viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );
                    _shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;
                    shadow.mapSize.x = _viewportSize.x;

                }

                if ( _shadowMapSize.y > _maxTextureSize ) {

                    _viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );
                    _shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;
                    shadow.mapSize.y = _viewportSize.y;

                }

            }

            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';

                shadow.camera.updateProjectionMatrix();

            }

            renderer.setRenderTarget( shadow.map );
            renderer.clear();

            const viewportCount = shadow.getViewportCount();

            for ( let vp = 0; vp < viewportCount; vp ++ ) {

                const viewport = shadow.getViewport( vp );

                _viewport.set(
                    _viewportSize.x * viewport.x,
                    _viewportSize.y * viewport.y,
                    _viewportSize.x * viewport.z,
                    _viewportSize.y * viewport.w
                );

                _state.viewport( _viewport );

                shadow.updateMatrices( light, vp );

                _frustum = shadow.getFrustum();

                renderObject( scene, camera, shadow.camera, light, this.type );

            }

            // do blur pass for VSM

            if ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {

                VSMPass( shadow, camera );

            }

            shadow.needsUpdate = false;

        }

        _previousType = this.type;

        scope.needsUpdate = false;

        renderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );

    };

    function VSMPass( shadow, camera ) {

        const geometry = objects.update( fullScreenMesh );

        if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {

            shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
            shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;

            shadowMaterialVertical.needsUpdate = true;
            shadowMaterialHorizontal.needsUpdate = true;

        }

        if ( shadow.mapPass === null ) {

            shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );

        }

        // vertical pass

        shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
        shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
        shadowMaterialVertical.uniforms.radius.value = shadow.radius;
        renderer.setRenderTarget( shadow.mapPass );
        renderer.clear();
        renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );

        // horizontal pass

        shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
        shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
        shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
        renderer.setRenderTarget( shadow.map );
        renderer.clear();
        renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );

    }

    function getDepthMaterial( object, material, light, type ) {

        let result = null;

        const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;

        if ( customMaterial !== undefined ) {

            result = customMaterial;

        } else {

            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 ) ||
                ( material.alphaToCoverage === true ) ) {

                // in this case we need a unique material instance reflecting the
                // appropriate state

                const keyA = result.uuid, keyB = material.uuid;

                let materialsForVariant = _materialCache[ keyA ];

                if ( materialsForVariant === undefined ) {

                    materialsForVariant = {};
                    _materialCache[ keyA ] = materialsForVariant;

                }

                let cachedMaterial = materialsForVariant[ keyB ];

                if ( cachedMaterial === undefined ) {

                    cachedMaterial = result.clone();
                    materialsForVariant[ keyB ] = cachedMaterial;
                    material.addEventListener( 'dispose', onMaterialDispose );

                }

                result = cachedMaterial;

            }

        }

        result.visible = material.visible;
        result.wireframe = material.wireframe;

        if ( type === VSMShadowMap ) {

            result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;

        } else {

            result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];

        }

        result.alphaMap = material.alphaMap;
        result.alphaTest = ( material.alphaToCoverage === true ) ? 0.5 : material.alphaTest; // approximate alphaToCoverage by using a fixed alphaTest value
        result.map = material.map;

        result.clipShadows = material.clipShadows;
        result.clippingPlanes = material.clippingPlanes;
        result.clipIntersection = material.clipIntersection;

        result.displacementMap = material.displacementMap;
        result.displacementScale = material.displacementScale;
        result.displacementBias = material.displacementBias;

        result.wireframeLinewidth = material.wireframeLinewidth;
        result.linewidth = material.linewidth;

        if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {

            const materialProperties = renderer.properties.get( result );
            materialProperties.light = light;

        }

        return result;

    }

    function renderObject( object, camera, shadowCamera, light, type ) {

        if ( object.visible === false ) return;

        const visible = object.layers.test( camera.layers );

        if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {

            if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {

                object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

                const geometry = objects.update( object );
                const material = object.material;

                if ( Array.isArray( material ) ) {

                    const groups = geometry.groups;

                    for ( let k = 0, kl = groups.length; k < kl; k ++ ) {

                        const group = groups[ k ];
                        const groupMaterial = material[ group.materialIndex ];

                        if ( groupMaterial && groupMaterial.visible ) {

                            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, 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 );

                }

            }

        }

        const children = object.children;

        for ( let i = 0, l = children.length; i < l; i ++ ) {

            renderObject( children[ i ], camera, shadowCamera, light, type );

        }

    }

    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 ];

            }

        }

    }

}

VSMPass(shadow: any, camera: any): void

Parameters:

  • shadow any
  • camera any

Returns: void

Calls:

  • objects.update
  • renderer.setRenderTarget
  • renderer.clear
  • renderer.renderBufferDirect

Internal Comments:

// vertical pass (x6)
// horizontal pass (x6)

Code
function VSMPass( shadow, camera ) {

        const geometry = objects.update( fullScreenMesh );

        if ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {

            shadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;
            shadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;

            shadowMaterialVertical.needsUpdate = true;
            shadowMaterialHorizontal.needsUpdate = true;

        }

        if ( shadow.mapPass === null ) {

            shadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );

        }

        // vertical pass

        shadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;
        shadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;
        shadowMaterialVertical.uniforms.radius.value = shadow.radius;
        renderer.setRenderTarget( shadow.mapPass );
        renderer.clear();
        renderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );

        // horizontal pass

        shadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;
        shadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;
        shadowMaterialHorizontal.uniforms.radius.value = shadow.radius;
        renderer.setRenderTarget( shadow.map );
        renderer.clear();
        renderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );

    }

getDepthMaterial(object: any, material: any, light: any, type: any): any

Parameters:

  • object any
  • material any
  • light any
  • type any

Returns: any

Calls:

  • Array.isArray
  • result.clone
  • material.addEventListener
  • renderer.properties.get

Internal Comments:

// in this case we need a unique material instance reflecting the (x2)
// appropriate state (x2)

Code
function getDepthMaterial( object, material, light, type ) {

        let result = null;

        const customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;

        if ( customMaterial !== undefined ) {

            result = customMaterial;

        } else {

            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 ) ||
                ( material.alphaToCoverage === true ) ) {

                // in this case we need a unique material instance reflecting the
                // appropriate state

                const keyA = result.uuid, keyB = material.uuid;

                let materialsForVariant = _materialCache[ keyA ];

                if ( materialsForVariant === undefined ) {

                    materialsForVariant = {};
                    _materialCache[ keyA ] = materialsForVariant;

                }

                let cachedMaterial = materialsForVariant[ keyB ];

                if ( cachedMaterial === undefined ) {

                    cachedMaterial = result.clone();
                    materialsForVariant[ keyB ] = cachedMaterial;
                    material.addEventListener( 'dispose', onMaterialDispose );

                }

                result = cachedMaterial;

            }

        }

        result.visible = material.visible;
        result.wireframe = material.wireframe;

        if ( type === VSMShadowMap ) {

            result.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;

        } else {

            result.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];

        }

        result.alphaMap = material.alphaMap;
        result.alphaTest = ( material.alphaToCoverage === true ) ? 0.5 : material.alphaTest; // approximate alphaToCoverage by using a fixed alphaTest value
        result.map = material.map;

        result.clipShadows = material.clipShadows;
        result.clippingPlanes = material.clippingPlanes;
        result.clipIntersection = material.clipIntersection;

        result.displacementMap = material.displacementMap;
        result.displacementScale = material.displacementScale;
        result.displacementBias = material.displacementBias;

        result.wireframeLinewidth = material.wireframeLinewidth;
        result.linewidth = material.linewidth;

        if ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {

            const materialProperties = renderer.properties.get( result );
            materialProperties.light = light;

        }

        return result;

    }

renderObject(object: any, camera: any, shadowCamera: any, light: any, type: any): void

Parameters:

  • object any
  • camera any
  • shadowCamera any
  • light any
  • type any

Returns: void

Calls:

  • object.layers.test
  • _frustum.intersectsObject
  • object.modelViewMatrix.multiplyMatrices
  • objects.update
  • Array.isArray
  • getDepthMaterial
  • object.onBeforeShadow
  • renderer.renderBufferDirect
  • object.onAfterShadow
  • renderObject
Code
function renderObject( object, camera, shadowCamera, light, type ) {

        if ( object.visible === false ) return;

        const visible = object.layers.test( camera.layers );

        if ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {

            if ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {

                object.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );

                const geometry = objects.update( object );
                const material = object.material;

                if ( Array.isArray( material ) ) {

                    const groups = geometry.groups;

                    for ( let k = 0, kl = groups.length; k < kl; k ++ ) {

                        const group = groups[ k ];
                        const groupMaterial = material[ group.materialIndex ];

                        if ( groupMaterial && groupMaterial.visible ) {

                            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, 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 );

                }

            }

        }

        const children = object.children;

        for ( let i = 0, l = children.length; i < l; i ++ ) {

            renderObject( children[ i ], camera, shadowCamera, light, type );

        }

    }

onMaterialDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • material.removeEventListener
  • shadowMaterial.dispose

Internal Comments:

// make sure to remove the unique distance/depth materials used for shadow map rendering

Code
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 ];

            }

        }

    }

WebGLState(gl: any, extensions: any): { buffers: { color: any; depth: any; stencil: any; }; enable: (id: any) => void; disable: (id: any) => void; bindFramebuffer: (target: any, framebuffer: any) => boolean; drawBuffers: (renderTarget: any, framebuffer: any) => void; ... 25 more ...; reset: () => void; }

Parameters:

  • gl any
  • extensions any

Returns: { buffers: { color: any; depth: any; stencil: any; }; enable: (id: any) => void; disable: (id: any) => void; bindFramebuffer: (target: any, framebuffer: any) => boolean; drawBuffers: (renderTarget: any, framebuffer: any) => void; ... 25 more ...; reset: () => void; }

Calls:

  • gl.colorMask
  • color.set
  • currentColorClear.equals
  • gl.clearColor
  • currentColorClear.copy
  • currentColorClear.set
  • extensions.get
  • ext.clipControlEXT
  • this.setClear
  • enable
  • disable
  • gl.depthMask
  • gl.depthFunc
  • gl.clearDepth
  • gl.stencilMask
  • gl.stencilFunc
  • gl.stencilOp
  • gl.clearStencil
  • gl.getParameter
  • glVersion.indexOf
  • parseFloat
  • /^WebGL (\d)/.exec
  • /^OpenGL ES (\d)/.exec
  • new Vector4().fromArray
  • gl.createTexture
  • gl.bindTexture
  • gl.texParameteri
  • gl.texImage3D
  • gl.texImage2D
  • createTexture
  • colorBuffer.setClear
  • depthBuffer.setClear
  • stencilBuffer.setClear
  • depthBuffer.setFunc
  • setFlipSided
  • setCullFace
  • setBlending
  • gl.enable
  • gl.disable
  • gl.bindFramebuffer
  • currentDrawbuffers.get
  • currentDrawbuffers.set
  • gl.drawBuffers
  • gl.useProgram
  • gl.blendEquation
  • gl.blendFuncSeparate
  • gl.blendFunc
  • console.error
  • currentBlendColor.set
  • gl.blendEquationSeparate
  • blendColor.equals
  • gl.blendColor
  • currentBlendColor.copy
  • depthBuffer.setTest
  • depthBuffer.setMask
  • colorBuffer.setMask
  • stencilBuffer.setTest
  • stencilBuffer.setMask
  • stencilBuffer.setFunc
  • stencilBuffer.setOp
  • setPolygonOffset
  • gl.frontFace
  • gl.cullFace
  • gl.lineWidth
  • gl.polygonOffset
  • gl.activeTexture
  • gl.compressedTexImage2D
  • gl.compressedTexImage3D
  • gl.texSubImage2D
  • gl.texSubImage3D
  • gl.compressedTexSubImage2D
  • gl.compressedTexSubImage3D
  • gl.texStorage2D
  • gl.texStorage3D
  • currentScissor.equals
  • gl.scissor
  • currentScissor.copy
  • currentViewport.equals
  • gl.viewport
  • currentViewport.copy
  • uboProgramMap.get
  • uboProgramMap.set
  • mapping.get
  • gl.getUniformBlockIndex
  • mapping.set
  • uboBindings.get
  • gl.uniformBlockBinding
  • uboBindings.set
  • depthBuffer.setReversed
  • currentScissor.set
  • currentViewport.set
  • colorBuffer.reset
  • depthBuffer.reset
  • stencilBuffer.reset

Internal Comments:

// (x6)
// init (x4)
// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER
// custom blending (x3)
// texture
// bind shader specific block index to global block point (x4)
// reset state (x4)
// reset internals (x3)

Code
function WebGLState( gl, extensions ) {

    function ColorBuffer() {

        let locked = false;

        const color = new Vector4();
        let currentColorMask = null;
        const currentColorClear = new Vector4( 0, 0, 0, 0 );

        return {

            setMask: function ( colorMask ) {

                if ( currentColorMask !== colorMask && ! locked ) {

                    gl.colorMask( colorMask, colorMask, colorMask, colorMask );
                    currentColorMask = colorMask;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( r, g, b, a, premultipliedAlpha ) {

                if ( premultipliedAlpha === true ) {

                    r *= a; g *= a; b *= a;

                }

                color.set( r, g, b, a );

                if ( currentColorClear.equals( color ) === false ) {

                    gl.clearColor( r, g, b, a );
                    currentColorClear.copy( color );

                }

            },

            reset: function () {

                locked = false;

                currentColorMask = null;
                currentColorClear.set( -1, 0, 0, 0 ); // set to invalid state

            }

        };

    }

    function DepthBuffer() {

        let locked = false;

        let currentReversed = false;
        let currentDepthMask = null;
        let currentDepthFunc = null;
        let currentDepthClear = null;

        return {

            setReversed: function ( reversed ) {

                if ( currentReversed !== reversed ) {

                    const ext = extensions.get( 'EXT_clip_control' );

                    if ( reversed ) {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );

                    } else {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT );

                    }

                    currentReversed = reversed;

                    const oldDepth = currentDepthClear;
                    currentDepthClear = null;
                    this.setClear( oldDepth );

                }

            },

            getReversed: function () {

                return currentReversed;

            },

            setTest: function ( depthTest ) {

                if ( depthTest ) {

                    enable( gl.DEPTH_TEST );

                } else {

                    disable( gl.DEPTH_TEST );

                }

            },

            setMask: function ( depthMask ) {

                if ( currentDepthMask !== depthMask && ! locked ) {

                    gl.depthMask( depthMask );
                    currentDepthMask = depthMask;

                }

            },

            setFunc: function ( depthFunc ) {

                if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];

                if ( currentDepthFunc !== depthFunc ) {

                    switch ( depthFunc ) {

                        case NeverDepth:

                            gl.depthFunc( gl.NEVER );
                            break;

                        case AlwaysDepth:

                            gl.depthFunc( gl.ALWAYS );
                            break;

                        case LessDepth:

                            gl.depthFunc( gl.LESS );
                            break;

                        case LessEqualDepth:

                            gl.depthFunc( gl.LEQUAL );
                            break;

                        case EqualDepth:

                            gl.depthFunc( gl.EQUAL );
                            break;

                        case GreaterEqualDepth:

                            gl.depthFunc( gl.GEQUAL );
                            break;

                        case GreaterDepth:

                            gl.depthFunc( gl.GREATER );
                            break;

                        case NotEqualDepth:

                            gl.depthFunc( gl.NOTEQUAL );
                            break;

                        default:

                            gl.depthFunc( gl.LEQUAL );

                    }

                    currentDepthFunc = depthFunc;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( depth ) {

                if ( currentDepthClear !== depth ) {

                    if ( currentReversed ) {

                        depth = 1 - depth;

                    }

                    gl.clearDepth( depth );
                    currentDepthClear = depth;

                }

            },

            reset: function () {

                locked = false;

                currentDepthMask = null;
                currentDepthFunc = null;
                currentDepthClear = null;
                currentReversed = false;

            }

        };

    }

    function StencilBuffer() {

        let locked = false;

        let currentStencilMask = null;
        let currentStencilFunc = null;
        let currentStencilRef = null;
        let currentStencilFuncMask = null;
        let currentStencilFail = null;
        let currentStencilZFail = null;
        let currentStencilZPass = null;
        let currentStencilClear = null;

        return {

            setTest: function ( stencilTest ) {

                if ( ! locked ) {

                    if ( stencilTest ) {

                        enable( gl.STENCIL_TEST );

                    } else {

                        disable( gl.STENCIL_TEST );

                    }

                }

            },

            setMask: function ( stencilMask ) {

                if ( currentStencilMask !== stencilMask && ! locked ) {

                    gl.stencilMask( stencilMask );
                    currentStencilMask = stencilMask;

                }

            },

            setFunc: function ( stencilFunc, stencilRef, stencilMask ) {

                if ( currentStencilFunc !== stencilFunc ||
                     currentStencilRef !== stencilRef ||
                     currentStencilFuncMask !== stencilMask ) {

                    gl.stencilFunc( stencilFunc, stencilRef, stencilMask );

                    currentStencilFunc = stencilFunc;
                    currentStencilRef = stencilRef;
                    currentStencilFuncMask = stencilMask;

                }

            },

            setOp: function ( stencilFail, stencilZFail, stencilZPass ) {

                if ( currentStencilFail !== stencilFail ||
                     currentStencilZFail !== stencilZFail ||
                     currentStencilZPass !== stencilZPass ) {

                    gl.stencilOp( stencilFail, stencilZFail, stencilZPass );

                    currentStencilFail = stencilFail;
                    currentStencilZFail = stencilZFail;
                    currentStencilZPass = stencilZPass;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( stencil ) {

                if ( currentStencilClear !== stencil ) {

                    gl.clearStencil( stencil );
                    currentStencilClear = stencil;

                }

            },

            reset: function () {

                locked = false;

                currentStencilMask = null;
                currentStencilFunc = null;
                currentStencilRef = null;
                currentStencilFuncMask = null;
                currentStencilFail = null;
                currentStencilZFail = null;
                currentStencilZPass = null;
                currentStencilClear = null;

            }

        };

    }

    //

    const colorBuffer = new ColorBuffer();
    const depthBuffer = new DepthBuffer();
    const stencilBuffer = new StencilBuffer();

    const uboBindings = new WeakMap();
    const uboProgramMap = new WeakMap();

    let enabledCapabilities = {};

    let currentBoundFramebuffers = {};
    let currentDrawbuffers = new WeakMap();
    let defaultDrawbuffers = [];

    let currentProgram = null;

    let currentBlendingEnabled = false;
    let currentBlending = null;
    let currentBlendEquation = null;
    let currentBlendSrc = null;
    let currentBlendDst = null;
    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;
    let currentCullFace = null;

    let currentLineWidth = null;

    let currentPolygonOffsetFactor = null;
    let currentPolygonOffsetUnits = null;

    const maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );

    let lineWidthAvailable = false;
    let version = 0;
    const glVersion = gl.getParameter( gl.VERSION );

    if ( glVersion.indexOf( 'WebGL' ) !== -1 ) {

        version = parseFloat( /^WebGL (\d)/.exec( glVersion )[ 1 ] );
        lineWidthAvailable = ( version >= 1.0 );

    } else if ( glVersion.indexOf( 'OpenGL ES' ) !== -1 ) {

        version = parseFloat( /^OpenGL ES (\d)/.exec( glVersion )[ 1 ] );
        lineWidthAvailable = ( version >= 2.0 );

    }

    let currentTextureSlot = null;
    let currentBoundTextures = {};

    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, 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, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
        gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );

        for ( let i = 0; i < count; i ++ ) {

            if ( 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 );

            }

        }

        return texture;

    }

    const emptyTextures = {};
    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 );
    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

    colorBuffer.setClear( 0, 0, 0, 1 );
    depthBuffer.setClear( 1 );
    stencilBuffer.setClear( 0 );

    enable( gl.DEPTH_TEST );
    depthBuffer.setFunc( LessEqualDepth );

    setFlipSided( false );
    setCullFace( CullFaceBack );
    enable( gl.CULL_FACE );

    setBlending( NoBlending );

    //

    function enable( id ) {

        if ( enabledCapabilities[ id ] !== true ) {

            gl.enable( id );
            enabledCapabilities[ id ] = true;

        }

    }

    function disable( id ) {

        if ( enabledCapabilities[ id ] !== false ) {

            gl.disable( id );
            enabledCapabilities[ id ] = false;

        }

    }

    function bindFramebuffer( target, framebuffer ) {

        if ( currentBoundFramebuffers[ target ] !== framebuffer ) {

            gl.bindFramebuffer( target, framebuffer );

            currentBoundFramebuffers[ target ] = framebuffer;

            // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER

            if ( target === gl.DRAW_FRAMEBUFFER ) {

                currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;

            }

            if ( target === gl.FRAMEBUFFER ) {

                currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;

            }

            return true;

        }

        return false;

    }

    function drawBuffers( renderTarget, framebuffer ) {

        let drawBuffers = defaultDrawbuffers;

        let needsUpdate = false;

        if ( renderTarget ) {

            drawBuffers = currentDrawbuffers.get( framebuffer );

            if ( drawBuffers === undefined ) {

                drawBuffers = [];
                currentDrawbuffers.set( framebuffer, drawBuffers );

            }

            const textures = renderTarget.textures;

            if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {

                for ( let i = 0, il = textures.length; i < il; i ++ ) {

                    drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;

                }

                drawBuffers.length = textures.length;

                needsUpdate = true;

            }

        } else {

            if ( drawBuffers[ 0 ] !== gl.BACK ) {

                drawBuffers[ 0 ] = gl.BACK;

                needsUpdate = true;

            }

        }

        if ( needsUpdate ) {

            gl.drawBuffers( drawBuffers );

        }

    }

    function useProgram( program ) {

        if ( currentProgram !== program ) {

            gl.useProgram( program );

            currentProgram = program;

            return true;

        }

        return false;

    }

    const equationToGL = {
        [ AddEquation ]: gl.FUNC_ADD,
        [ SubtractEquation ]: gl.FUNC_SUBTRACT,
        [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT
    };

    equationToGL[ MinEquation ] = gl.MIN;
    equationToGL[ MaxEquation ] = gl.MAX;

    const factorToGL = {
        [ ZeroFactor ]: gl.ZERO,
        [ OneFactor ]: gl.ONE,
        [ SrcColorFactor ]: gl.SRC_COLOR,
        [ SrcAlphaFactor ]: gl.SRC_ALPHA,
        [ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,
        [ DstColorFactor ]: gl.DST_COLOR,
        [ DstAlphaFactor ]: gl.DST_ALPHA,
        [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,
        [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,
        [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,
        [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,
        [ ConstantColorFactor ]: gl.CONSTANT_COLOR,
        [ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,
        [ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,
        [ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA
    };

    function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {

        if ( blending === NoBlending ) {

            if ( currentBlendingEnabled === true ) {

                disable( gl.BLEND );
                currentBlendingEnabled = false;

            }

            return;

        }

        if ( currentBlendingEnabled === false ) {

            enable( gl.BLEND );
            currentBlendingEnabled = true;

        }

        if ( blending !== CustomBlending ) {

            if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {

                if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {

                    gl.blendEquation( gl.FUNC_ADD );

                    currentBlendEquation = AddEquation;
                    currentBlendEquationAlpha = AddEquation;

                }

                if ( premultipliedAlpha ) {

                    switch ( blending ) {

                        case NormalBlending:
                            gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
                            break;

                        case AdditiveBlending:
                            gl.blendFunc( gl.ONE, gl.ONE );
                            break;

                        case SubtractiveBlending:
                            gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
                            break;

                        case MultiplyBlending:
                            gl.blendFuncSeparate( gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE );
                            break;

                        default:
                            console.error( 'THREE.WebGLState: Invalid blending: ', blending );
                            break;

                    }

                } else {

                    switch ( blending ) {

                        case NormalBlending:
                            gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
                            break;

                        case AdditiveBlending:
                            gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE );
                            break;

                        case SubtractiveBlending:
                            console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' );
                            break;

                        case MultiplyBlending:
                            console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' );
                            break;

                        default:
                            console.error( 'THREE.WebGLState: Invalid blending: ', blending );
                            break;

                    }

                }

                currentBlendSrc = null;
                currentBlendDst = null;
                currentBlendSrcAlpha = null;
                currentBlendDstAlpha = null;
                currentBlendColor.set( 0, 0, 0 );
                currentBlendAlpha = 0;

                currentBlending = blending;
                currentPremultipledAlpha = premultipliedAlpha;

            }

            return;

        }

        // custom blending

        blendEquationAlpha = blendEquationAlpha || blendEquation;
        blendSrcAlpha = blendSrcAlpha || blendSrc;
        blendDstAlpha = blendDstAlpha || blendDst;

        if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {

            gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );

            currentBlendEquation = blendEquation;
            currentBlendEquationAlpha = blendEquationAlpha;

        }

        if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {

            gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );

            currentBlendSrc = blendSrc;
            currentBlendDst = blendDst;
            currentBlendSrcAlpha = blendSrcAlpha;
            currentBlendDstAlpha = blendDstAlpha;

        }

        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;

    }

    function setMaterial( material, frontFaceCW ) {

        material.side === DoubleSide
            ? disable( gl.CULL_FACE )
            : enable( gl.CULL_FACE );

        let flipSided = ( material.side === BackSide );
        if ( frontFaceCW ) flipSided = ! flipSided;

        setFlipSided( flipSided );

        ( material.blending === NormalBlending && material.transparent === false )
            ? setBlending( NoBlending )
            : 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 );
        depthBuffer.setMask( material.depthWrite );
        colorBuffer.setMask( material.colorWrite );

        const stencilWrite = material.stencilWrite;
        stencilBuffer.setTest( stencilWrite );
        if ( stencilWrite ) {

            stencilBuffer.setMask( material.stencilWriteMask );
            stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
            stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );

        }

        setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

        material.alphaToCoverage === true
            ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
            : disable( gl.SAMPLE_ALPHA_TO_COVERAGE );

    }

    //

    function setFlipSided( flipSided ) {

        if ( currentFlipSided !== flipSided ) {

            if ( flipSided ) {

                gl.frontFace( gl.CW );

            } else {

                gl.frontFace( gl.CCW );

            }

            currentFlipSided = flipSided;

        }

    }

    function setCullFace( cullFace ) {

        if ( cullFace !== CullFaceNone ) {

            enable( gl.CULL_FACE );

            if ( cullFace !== currentCullFace ) {

                if ( cullFace === CullFaceBack ) {

                    gl.cullFace( gl.BACK );

                } else if ( cullFace === CullFaceFront ) {

                    gl.cullFace( gl.FRONT );

                } else {

                    gl.cullFace( gl.FRONT_AND_BACK );

                }

            }

        } else {

            disable( gl.CULL_FACE );

        }

        currentCullFace = cullFace;

    }

    function setLineWidth( width ) {

        if ( width !== currentLineWidth ) {

            if ( lineWidthAvailable ) gl.lineWidth( width );

            currentLineWidth = width;

        }

    }

    function setPolygonOffset( polygonOffset, factor, units ) {

        if ( polygonOffset ) {

            enable( gl.POLYGON_OFFSET_FILL );

            if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {

                gl.polygonOffset( factor, units );

                currentPolygonOffsetFactor = factor;
                currentPolygonOffsetUnits = units;

            }

        } else {

            disable( gl.POLYGON_OFFSET_FILL );

        }

    }

    function setScissorTest( scissorTest ) {

        if ( scissorTest ) {

            enable( gl.SCISSOR_TEST );

        } else {

            disable( gl.SCISSOR_TEST );

        }

    }

    // texture

    function activeTexture( webglSlot ) {

        if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;

        if ( currentTextureSlot !== webglSlot ) {

            gl.activeTexture( webglSlot );
            currentTextureSlot = webglSlot;

        }

    }

    function bindTexture( webglType, webglTexture, webglSlot ) {

        if ( webglSlot === undefined ) {

            if ( currentTextureSlot === null ) {

                webglSlot = gl.TEXTURE0 + maxTextures - 1;

            } else {

                webglSlot = currentTextureSlot;

            }

        }

        let boundTexture = currentBoundTextures[ webglSlot ];

        if ( boundTexture === undefined ) {

            boundTexture = { type: undefined, texture: undefined };
            currentBoundTextures[ webglSlot ] = boundTexture;

        }

        if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {

            if ( currentTextureSlot !== webglSlot ) {

                gl.activeTexture( webglSlot );
                currentTextureSlot = webglSlot;

            }

            gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );

            boundTexture.type = webglType;
            boundTexture.texture = webglTexture;

        }

    }

    function unbindTexture() {

        const boundTexture = currentBoundTextures[ currentTextureSlot ];

        if ( boundTexture !== undefined && boundTexture.type !== undefined ) {

            gl.bindTexture( boundTexture.type, null );

            boundTexture.type = undefined;
            boundTexture.texture = undefined;

        }

    }

    function compressedTexImage2D() {

        try {

            gl.compressedTexImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function compressedTexImage3D() {

        try {

            gl.compressedTexImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texSubImage2D() {

        try {

            gl.texSubImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texSubImage3D() {

        try {

            gl.texSubImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function compressedTexSubImage2D() {

        try {

            gl.compressedTexSubImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function compressedTexSubImage3D() {

        try {

            gl.compressedTexSubImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texStorage2D() {

        try {

            gl.texStorage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texStorage3D() {

        try {

            gl.texStorage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texImage2D() {

        try {

            gl.texImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    function texImage3D() {

        try {

            gl.texImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

    //

    function scissor( scissor ) {

        if ( currentScissor.equals( scissor ) === false ) {

            gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
            currentScissor.copy( scissor );

        }

    }

    function viewport( viewport ) {

        if ( currentViewport.equals( viewport ) === false ) {

            gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
            currentViewport.copy( viewport );

        }

    }

    function updateUBOMapping( uniformsGroup, program ) {

        let mapping = uboProgramMap.get( program );

        if ( mapping === undefined ) {

            mapping = new WeakMap();

            uboProgramMap.set( program, mapping );

        }

        let blockIndex = mapping.get( uniformsGroup );

        if ( blockIndex === undefined ) {

            blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );

            mapping.set( uniformsGroup, blockIndex );

        }

    }

    function uniformBlockBinding( uniformsGroup, program ) {

        const mapping = uboProgramMap.get( program );
        const blockIndex = mapping.get( uniformsGroup );

        if ( uboBindings.get( program ) !== blockIndex ) {

            // bind shader specific block index to global block point
            gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );

            uboBindings.set( program, blockIndex );

        }

    }

    //

    function reset() {

        // reset state

        gl.disable( gl.BLEND );
        gl.disable( gl.CULL_FACE );
        gl.disable( gl.DEPTH_TEST );
        gl.disable( gl.POLYGON_OFFSET_FILL );
        gl.disable( gl.SCISSOR_TEST );
        gl.disable( gl.STENCIL_TEST );
        gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );

        gl.blendEquation( gl.FUNC_ADD );
        gl.blendFunc( gl.ONE, gl.ZERO );
        gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
        gl.blendColor( 0, 0, 0, 0 );

        gl.colorMask( true, true, true, true );
        gl.clearColor( 0, 0, 0, 0 );

        gl.depthMask( true );
        gl.depthFunc( gl.LESS );

        depthBuffer.setReversed( false );

        gl.clearDepth( 1 );

        gl.stencilMask( 0xffffffff );
        gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
        gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
        gl.clearStencil( 0 );

        gl.cullFace( gl.BACK );
        gl.frontFace( gl.CCW );

        gl.polygonOffset( 0, 0 );

        gl.activeTexture( gl.TEXTURE0 );

        gl.bindFramebuffer( gl.FRAMEBUFFER, null );
        gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
        gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );

        gl.useProgram( null );

        gl.lineWidth( 1 );

        gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
        gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );

        // reset internals

        enabledCapabilities = {};

        currentTextureSlot = null;
        currentBoundTextures = {};

        currentBoundFramebuffers = {};
        currentDrawbuffers = new WeakMap();
        defaultDrawbuffers = [];

        currentProgram = null;

        currentBlendingEnabled = false;
        currentBlending = null;
        currentBlendEquation = null;
        currentBlendSrc = null;
        currentBlendDst = null;
        currentBlendEquationAlpha = null;
        currentBlendSrcAlpha = null;
        currentBlendDstAlpha = null;
        currentBlendColor = new Color( 0, 0, 0 );
        currentBlendAlpha = 0;
        currentPremultipledAlpha = false;

        currentFlipSided = null;
        currentCullFace = null;

        currentLineWidth = null;

        currentPolygonOffsetFactor = null;
        currentPolygonOffsetUnits = null;

        currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
        currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );

        colorBuffer.reset();
        depthBuffer.reset();
        stencilBuffer.reset();

    }

    return {

        buffers: {
            color: colorBuffer,
            depth: depthBuffer,
            stencil: stencilBuffer
        },

        enable: enable,
        disable: disable,

        bindFramebuffer: bindFramebuffer,
        drawBuffers: drawBuffers,

        useProgram: useProgram,

        setBlending: setBlending,
        setMaterial: setMaterial,

        setFlipSided: setFlipSided,
        setCullFace: setCullFace,

        setLineWidth: setLineWidth,
        setPolygonOffset: setPolygonOffset,

        setScissorTest: setScissorTest,

        activeTexture: activeTexture,
        bindTexture: bindTexture,
        unbindTexture: unbindTexture,
        compressedTexImage2D: compressedTexImage2D,
        compressedTexImage3D: compressedTexImage3D,
        texImage2D: texImage2D,
        texImage3D: texImage3D,

        updateUBOMapping: updateUBOMapping,
        uniformBlockBinding: uniformBlockBinding,

        texStorage2D: texStorage2D,
        texStorage3D: texStorage3D,
        texSubImage2D: texSubImage2D,
        texSubImage3D: texSubImage3D,
        compressedTexSubImage2D: compressedTexSubImage2D,
        compressedTexSubImage3D: compressedTexSubImage3D,

        scissor: scissor,
        viewport: viewport,

        reset: reset

    };

}

ColorBuffer(): { setMask: (colorMask: any) => void; setLocked: (lock: any) => void; setClear: (r: any, g: any, b: any, a: any, premultipliedAlpha: any) => void; reset: () => void; }

Returns: { setMask: (colorMask: any) => void; setLocked: (lock: any) => void; setClear: (r: any, g: any, b: any, a: any, premultipliedAlpha: any) => void; reset: () => void; }

Calls:

  • gl.colorMask
  • color.set
  • currentColorClear.equals
  • gl.clearColor
  • currentColorClear.copy
  • currentColorClear.set
Code
function ColorBuffer() {

        let locked = false;

        const color = new Vector4();
        let currentColorMask = null;
        const currentColorClear = new Vector4( 0, 0, 0, 0 );

        return {

            setMask: function ( colorMask ) {

                if ( currentColorMask !== colorMask && ! locked ) {

                    gl.colorMask( colorMask, colorMask, colorMask, colorMask );
                    currentColorMask = colorMask;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( r, g, b, a, premultipliedAlpha ) {

                if ( premultipliedAlpha === true ) {

                    r *= a; g *= a; b *= a;

                }

                color.set( r, g, b, a );

                if ( currentColorClear.equals( color ) === false ) {

                    gl.clearColor( r, g, b, a );
                    currentColorClear.copy( color );

                }

            },

            reset: function () {

                locked = false;

                currentColorMask = null;
                currentColorClear.set( -1, 0, 0, 0 ); // set to invalid state

            }

        };

    }

setMask(colorMask: any): void

Parameters:

  • colorMask any

Returns: void

Calls:

  • gl.colorMask
Code
function ( colorMask ) {

                if ( currentColorMask !== colorMask && ! locked ) {

                    gl.colorMask( colorMask, colorMask, colorMask, colorMask );
                    currentColorMask = colorMask;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(r: any, g: any, b: any, a: any, premultipliedAlpha: any): void

Parameters:

  • r any
  • g any
  • b any
  • a any
  • premultipliedAlpha any

Returns: void

Calls:

  • color.set
  • currentColorClear.equals
  • gl.clearColor
  • currentColorClear.copy
Code
function ( r, g, b, a, premultipliedAlpha ) {

                if ( premultipliedAlpha === true ) {

                    r *= a; g *= a; b *= a;

                }

                color.set( r, g, b, a );

                if ( currentColorClear.equals( color ) === false ) {

                    gl.clearColor( r, g, b, a );
                    currentColorClear.copy( color );

                }

            }

reset(): void

Returns: void

Calls:

  • currentColorClear.set
Code
function () {

                locked = false;

                currentColorMask = null;
                currentColorClear.set( -1, 0, 0, 0 ); // set to invalid state

            }

setMask(colorMask: any): void

Parameters:

  • colorMask any

Returns: void

Calls:

  • gl.colorMask
Code
function ( colorMask ) {

                if ( currentColorMask !== colorMask && ! locked ) {

                    gl.colorMask( colorMask, colorMask, colorMask, colorMask );
                    currentColorMask = colorMask;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(r: any, g: any, b: any, a: any, premultipliedAlpha: any): void

Parameters:

  • r any
  • g any
  • b any
  • a any
  • premultipliedAlpha any

Returns: void

Calls:

  • color.set
  • currentColorClear.equals
  • gl.clearColor
  • currentColorClear.copy
Code
function ( r, g, b, a, premultipliedAlpha ) {

                if ( premultipliedAlpha === true ) {

                    r *= a; g *= a; b *= a;

                }

                color.set( r, g, b, a );

                if ( currentColorClear.equals( color ) === false ) {

                    gl.clearColor( r, g, b, a );
                    currentColorClear.copy( color );

                }

            }

reset(): void

Returns: void

Calls:

  • currentColorClear.set
Code
function () {

                locked = false;

                currentColorMask = null;
                currentColorClear.set( -1, 0, 0, 0 ); // set to invalid state

            }

DepthBuffer(): { setReversed: (reversed: any) => void; getReversed: () => boolean; setTest: (depthTest: any) => void; setMask: (depthMask: any) => void; setFunc: (depthFunc: any) => void; setLocked: (lock: any) => void; setClear: (depth: any) => void; reset: () => void; }

Returns: { setReversed: (reversed: any) => void; getReversed: () => boolean; setTest: (depthTest: any) => void; setMask: (depthMask: any) => void; setFunc: (depthFunc: any) => void; setLocked: (lock: any) => void; setClear: (depth: any) => void; reset: () => void; }

Calls:

  • extensions.get
  • ext.clipControlEXT
  • this.setClear
  • enable
  • disable
  • gl.depthMask
  • gl.depthFunc
  • gl.clearDepth
Code
function DepthBuffer() {

        let locked = false;

        let currentReversed = false;
        let currentDepthMask = null;
        let currentDepthFunc = null;
        let currentDepthClear = null;

        return {

            setReversed: function ( reversed ) {

                if ( currentReversed !== reversed ) {

                    const ext = extensions.get( 'EXT_clip_control' );

                    if ( reversed ) {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );

                    } else {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT );

                    }

                    currentReversed = reversed;

                    const oldDepth = currentDepthClear;
                    currentDepthClear = null;
                    this.setClear( oldDepth );

                }

            },

            getReversed: function () {

                return currentReversed;

            },

            setTest: function ( depthTest ) {

                if ( depthTest ) {

                    enable( gl.DEPTH_TEST );

                } else {

                    disable( gl.DEPTH_TEST );

                }

            },

            setMask: function ( depthMask ) {

                if ( currentDepthMask !== depthMask && ! locked ) {

                    gl.depthMask( depthMask );
                    currentDepthMask = depthMask;

                }

            },

            setFunc: function ( depthFunc ) {

                if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];

                if ( currentDepthFunc !== depthFunc ) {

                    switch ( depthFunc ) {

                        case NeverDepth:

                            gl.depthFunc( gl.NEVER );
                            break;

                        case AlwaysDepth:

                            gl.depthFunc( gl.ALWAYS );
                            break;

                        case LessDepth:

                            gl.depthFunc( gl.LESS );
                            break;

                        case LessEqualDepth:

                            gl.depthFunc( gl.LEQUAL );
                            break;

                        case EqualDepth:

                            gl.depthFunc( gl.EQUAL );
                            break;

                        case GreaterEqualDepth:

                            gl.depthFunc( gl.GEQUAL );
                            break;

                        case GreaterDepth:

                            gl.depthFunc( gl.GREATER );
                            break;

                        case NotEqualDepth:

                            gl.depthFunc( gl.NOTEQUAL );
                            break;

                        default:

                            gl.depthFunc( gl.LEQUAL );

                    }

                    currentDepthFunc = depthFunc;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( depth ) {

                if ( currentDepthClear !== depth ) {

                    if ( currentReversed ) {

                        depth = 1 - depth;

                    }

                    gl.clearDepth( depth );
                    currentDepthClear = depth;

                }

            },

            reset: function () {

                locked = false;

                currentDepthMask = null;
                currentDepthFunc = null;
                currentDepthClear = null;
                currentReversed = false;

            }

        };

    }

setReversed(reversed: any): void

Parameters:

  • reversed any

Returns: void

Calls:

  • extensions.get
  • ext.clipControlEXT
  • this.setClear
Code
function ( reversed ) {

                if ( currentReversed !== reversed ) {

                    const ext = extensions.get( 'EXT_clip_control' );

                    if ( reversed ) {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );

                    } else {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT );

                    }

                    currentReversed = reversed;

                    const oldDepth = currentDepthClear;
                    currentDepthClear = null;
                    this.setClear( oldDepth );

                }

            }

getReversed(): boolean

Returns: boolean

Code
function () {

                return currentReversed;

            }

setTest(depthTest: any): void

Parameters:

  • depthTest any

Returns: void

Calls:

  • enable
  • disable
Code
function ( depthTest ) {

                if ( depthTest ) {

                    enable( gl.DEPTH_TEST );

                } else {

                    disable( gl.DEPTH_TEST );

                }

            }

setMask(depthMask: any): void

Parameters:

  • depthMask any

Returns: void

Calls:

  • gl.depthMask
Code
function ( depthMask ) {

                if ( currentDepthMask !== depthMask && ! locked ) {

                    gl.depthMask( depthMask );
                    currentDepthMask = depthMask;

                }

            }

setFunc(depthFunc: any): void

Parameters:

  • depthFunc any

Returns: void

Calls:

  • gl.depthFunc
Code
function ( depthFunc ) {

                if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];

                if ( currentDepthFunc !== depthFunc ) {

                    switch ( depthFunc ) {

                        case NeverDepth:

                            gl.depthFunc( gl.NEVER );
                            break;

                        case AlwaysDepth:

                            gl.depthFunc( gl.ALWAYS );
                            break;

                        case LessDepth:

                            gl.depthFunc( gl.LESS );
                            break;

                        case LessEqualDepth:

                            gl.depthFunc( gl.LEQUAL );
                            break;

                        case EqualDepth:

                            gl.depthFunc( gl.EQUAL );
                            break;

                        case GreaterEqualDepth:

                            gl.depthFunc( gl.GEQUAL );
                            break;

                        case GreaterDepth:

                            gl.depthFunc( gl.GREATER );
                            break;

                        case NotEqualDepth:

                            gl.depthFunc( gl.NOTEQUAL );
                            break;

                        default:

                            gl.depthFunc( gl.LEQUAL );

                    }

                    currentDepthFunc = depthFunc;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(depth: any): void

Parameters:

  • depth any

Returns: void

Calls:

  • gl.clearDepth
Code
function ( depth ) {

                if ( currentDepthClear !== depth ) {

                    if ( currentReversed ) {

                        depth = 1 - depth;

                    }

                    gl.clearDepth( depth );
                    currentDepthClear = depth;

                }

            }

reset(): void

Returns: void

Code
function () {

                locked = false;

                currentDepthMask = null;
                currentDepthFunc = null;
                currentDepthClear = null;
                currentReversed = false;

            }

setReversed(reversed: any): void

Parameters:

  • reversed any

Returns: void

Calls:

  • extensions.get
  • ext.clipControlEXT
  • this.setClear
Code
function ( reversed ) {

                if ( currentReversed !== reversed ) {

                    const ext = extensions.get( 'EXT_clip_control' );

                    if ( reversed ) {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.ZERO_TO_ONE_EXT );

                    } else {

                        ext.clipControlEXT( ext.LOWER_LEFT_EXT, ext.NEGATIVE_ONE_TO_ONE_EXT );

                    }

                    currentReversed = reversed;

                    const oldDepth = currentDepthClear;
                    currentDepthClear = null;
                    this.setClear( oldDepth );

                }

            }

getReversed(): boolean

Returns: boolean

Code
function () {

                return currentReversed;

            }

setTest(depthTest: any): void

Parameters:

  • depthTest any

Returns: void

Calls:

  • enable
  • disable
Code
function ( depthTest ) {

                if ( depthTest ) {

                    enable( gl.DEPTH_TEST );

                } else {

                    disable( gl.DEPTH_TEST );

                }

            }

setMask(depthMask: any): void

Parameters:

  • depthMask any

Returns: void

Calls:

  • gl.depthMask
Code
function ( depthMask ) {

                if ( currentDepthMask !== depthMask && ! locked ) {

                    gl.depthMask( depthMask );
                    currentDepthMask = depthMask;

                }

            }

setFunc(depthFunc: any): void

Parameters:

  • depthFunc any

Returns: void

Calls:

  • gl.depthFunc
Code
function ( depthFunc ) {

                if ( currentReversed ) depthFunc = reversedFuncs[ depthFunc ];

                if ( currentDepthFunc !== depthFunc ) {

                    switch ( depthFunc ) {

                        case NeverDepth:

                            gl.depthFunc( gl.NEVER );
                            break;

                        case AlwaysDepth:

                            gl.depthFunc( gl.ALWAYS );
                            break;

                        case LessDepth:

                            gl.depthFunc( gl.LESS );
                            break;

                        case LessEqualDepth:

                            gl.depthFunc( gl.LEQUAL );
                            break;

                        case EqualDepth:

                            gl.depthFunc( gl.EQUAL );
                            break;

                        case GreaterEqualDepth:

                            gl.depthFunc( gl.GEQUAL );
                            break;

                        case GreaterDepth:

                            gl.depthFunc( gl.GREATER );
                            break;

                        case NotEqualDepth:

                            gl.depthFunc( gl.NOTEQUAL );
                            break;

                        default:

                            gl.depthFunc( gl.LEQUAL );

                    }

                    currentDepthFunc = depthFunc;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(depth: any): void

Parameters:

  • depth any

Returns: void

Calls:

  • gl.clearDepth
Code
function ( depth ) {

                if ( currentDepthClear !== depth ) {

                    if ( currentReversed ) {

                        depth = 1 - depth;

                    }

                    gl.clearDepth( depth );
                    currentDepthClear = depth;

                }

            }

reset(): void

Returns: void

Code
function () {

                locked = false;

                currentDepthMask = null;
                currentDepthFunc = null;
                currentDepthClear = null;
                currentReversed = false;

            }

StencilBuffer(): { setTest: (stencilTest: any) => void; setMask: (stencilMask: any) => void; setFunc: (stencilFunc: any, stencilRef: any, stencilMask: any) => void; setOp: (stencilFail: any, stencilZFail: any, stencilZPass: any) => void; setLocked: (lock: any) => void; setClear: (stencil: any) => void; reset: () => void; }

Returns: { setTest: (stencilTest: any) => void; setMask: (stencilMask: any) => void; setFunc: (stencilFunc: any, stencilRef: any, stencilMask: any) => void; setOp: (stencilFail: any, stencilZFail: any, stencilZPass: any) => void; setLocked: (lock: any) => void; setClear: (stencil: any) => void; reset: () => void; }

Calls:

  • enable
  • disable
  • gl.stencilMask
  • gl.stencilFunc
  • gl.stencilOp
  • gl.clearStencil
Code
function StencilBuffer() {

        let locked = false;

        let currentStencilMask = null;
        let currentStencilFunc = null;
        let currentStencilRef = null;
        let currentStencilFuncMask = null;
        let currentStencilFail = null;
        let currentStencilZFail = null;
        let currentStencilZPass = null;
        let currentStencilClear = null;

        return {

            setTest: function ( stencilTest ) {

                if ( ! locked ) {

                    if ( stencilTest ) {

                        enable( gl.STENCIL_TEST );

                    } else {

                        disable( gl.STENCIL_TEST );

                    }

                }

            },

            setMask: function ( stencilMask ) {

                if ( currentStencilMask !== stencilMask && ! locked ) {

                    gl.stencilMask( stencilMask );
                    currentStencilMask = stencilMask;

                }

            },

            setFunc: function ( stencilFunc, stencilRef, stencilMask ) {

                if ( currentStencilFunc !== stencilFunc ||
                     currentStencilRef !== stencilRef ||
                     currentStencilFuncMask !== stencilMask ) {

                    gl.stencilFunc( stencilFunc, stencilRef, stencilMask );

                    currentStencilFunc = stencilFunc;
                    currentStencilRef = stencilRef;
                    currentStencilFuncMask = stencilMask;

                }

            },

            setOp: function ( stencilFail, stencilZFail, stencilZPass ) {

                if ( currentStencilFail !== stencilFail ||
                     currentStencilZFail !== stencilZFail ||
                     currentStencilZPass !== stencilZPass ) {

                    gl.stencilOp( stencilFail, stencilZFail, stencilZPass );

                    currentStencilFail = stencilFail;
                    currentStencilZFail = stencilZFail;
                    currentStencilZPass = stencilZPass;

                }

            },

            setLocked: function ( lock ) {

                locked = lock;

            },

            setClear: function ( stencil ) {

                if ( currentStencilClear !== stencil ) {

                    gl.clearStencil( stencil );
                    currentStencilClear = stencil;

                }

            },

            reset: function () {

                locked = false;

                currentStencilMask = null;
                currentStencilFunc = null;
                currentStencilRef = null;
                currentStencilFuncMask = null;
                currentStencilFail = null;
                currentStencilZFail = null;
                currentStencilZPass = null;
                currentStencilClear = null;

            }

        };

    }

setTest(stencilTest: any): void

Parameters:

  • stencilTest any

Returns: void

Calls:

  • enable
  • disable
Code
function ( stencilTest ) {

                if ( ! locked ) {

                    if ( stencilTest ) {

                        enable( gl.STENCIL_TEST );

                    } else {

                        disable( gl.STENCIL_TEST );

                    }

                }

            }

setMask(stencilMask: any): void

Parameters:

  • stencilMask any

Returns: void

Calls:

  • gl.stencilMask
Code
function ( stencilMask ) {

                if ( currentStencilMask !== stencilMask && ! locked ) {

                    gl.stencilMask( stencilMask );
                    currentStencilMask = stencilMask;

                }

            }

setFunc(stencilFunc: any, stencilRef: any, stencilMask: any): void

Parameters:

  • stencilFunc any
  • stencilRef any
  • stencilMask any

Returns: void

Calls:

  • gl.stencilFunc
Code
function ( stencilFunc, stencilRef, stencilMask ) {

                if ( currentStencilFunc !== stencilFunc ||
                     currentStencilRef !== stencilRef ||
                     currentStencilFuncMask !== stencilMask ) {

                    gl.stencilFunc( stencilFunc, stencilRef, stencilMask );

                    currentStencilFunc = stencilFunc;
                    currentStencilRef = stencilRef;
                    currentStencilFuncMask = stencilMask;

                }

            }

setOp(stencilFail: any, stencilZFail: any, stencilZPass: any): void

Parameters:

  • stencilFail any
  • stencilZFail any
  • stencilZPass any

Returns: void

Calls:

  • gl.stencilOp
Code
function ( stencilFail, stencilZFail, stencilZPass ) {

                if ( currentStencilFail !== stencilFail ||
                     currentStencilZFail !== stencilZFail ||
                     currentStencilZPass !== stencilZPass ) {

                    gl.stencilOp( stencilFail, stencilZFail, stencilZPass );

                    currentStencilFail = stencilFail;
                    currentStencilZFail = stencilZFail;
                    currentStencilZPass = stencilZPass;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(stencil: any): void

Parameters:

  • stencil any

Returns: void

Calls:

  • gl.clearStencil
Code
function ( stencil ) {

                if ( currentStencilClear !== stencil ) {

                    gl.clearStencil( stencil );
                    currentStencilClear = stencil;

                }

            }

reset(): void

Returns: void

Code
function () {

                locked = false;

                currentStencilMask = null;
                currentStencilFunc = null;
                currentStencilRef = null;
                currentStencilFuncMask = null;
                currentStencilFail = null;
                currentStencilZFail = null;
                currentStencilZPass = null;
                currentStencilClear = null;

            }

setTest(stencilTest: any): void

Parameters:

  • stencilTest any

Returns: void

Calls:

  • enable
  • disable
Code
function ( stencilTest ) {

                if ( ! locked ) {

                    if ( stencilTest ) {

                        enable( gl.STENCIL_TEST );

                    } else {

                        disable( gl.STENCIL_TEST );

                    }

                }

            }

setMask(stencilMask: any): void

Parameters:

  • stencilMask any

Returns: void

Calls:

  • gl.stencilMask
Code
function ( stencilMask ) {

                if ( currentStencilMask !== stencilMask && ! locked ) {

                    gl.stencilMask( stencilMask );
                    currentStencilMask = stencilMask;

                }

            }

setFunc(stencilFunc: any, stencilRef: any, stencilMask: any): void

Parameters:

  • stencilFunc any
  • stencilRef any
  • stencilMask any

Returns: void

Calls:

  • gl.stencilFunc
Code
function ( stencilFunc, stencilRef, stencilMask ) {

                if ( currentStencilFunc !== stencilFunc ||
                     currentStencilRef !== stencilRef ||
                     currentStencilFuncMask !== stencilMask ) {

                    gl.stencilFunc( stencilFunc, stencilRef, stencilMask );

                    currentStencilFunc = stencilFunc;
                    currentStencilRef = stencilRef;
                    currentStencilFuncMask = stencilMask;

                }

            }

setOp(stencilFail: any, stencilZFail: any, stencilZPass: any): void

Parameters:

  • stencilFail any
  • stencilZFail any
  • stencilZPass any

Returns: void

Calls:

  • gl.stencilOp
Code
function ( stencilFail, stencilZFail, stencilZPass ) {

                if ( currentStencilFail !== stencilFail ||
                     currentStencilZFail !== stencilZFail ||
                     currentStencilZPass !== stencilZPass ) {

                    gl.stencilOp( stencilFail, stencilZFail, stencilZPass );

                    currentStencilFail = stencilFail;
                    currentStencilZFail = stencilZFail;
                    currentStencilZPass = stencilZPass;

                }

            }

setLocked(lock: any): void

Parameters:

  • lock any

Returns: void

Code
function ( lock ) {

                locked = lock;

            }

setClear(stencil: any): void

Parameters:

  • stencil any

Returns: void

Calls:

  • gl.clearStencil
Code
function ( stencil ) {

                if ( currentStencilClear !== stencil ) {

                    gl.clearStencil( stencil );
                    currentStencilClear = stencil;

                }

            }

reset(): void

Returns: void

Code
function () {

                locked = false;

                currentStencilMask = null;
                currentStencilFunc = null;
                currentStencilRef = null;
                currentStencilFuncMask = null;
                currentStencilFail = null;
                currentStencilZFail = null;
                currentStencilZPass = null;
                currentStencilClear = null;

            }

createTexture(type: any, target: any, count: any, dimensions: any): any

Parameters:

  • type any
  • target any
  • count any
  • dimensions any

Returns: any

Calls:

  • gl.createTexture
  • gl.bindTexture
  • gl.texParameteri
  • gl.texImage3D
  • gl.texImage2D
Code
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, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
        gl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );

        for ( let i = 0; i < count; i ++ ) {

            if ( 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 );

            }

        }

        return texture;

    }

enable(id: any): void

Parameters:

  • id any

Returns: void

Calls:

  • gl.enable
Code
function enable( id ) {

        if ( enabledCapabilities[ id ] !== true ) {

            gl.enable( id );
            enabledCapabilities[ id ] = true;

        }

    }

disable(id: any): void

Parameters:

  • id any

Returns: void

Calls:

  • gl.disable
Code
function disable( id ) {

        if ( enabledCapabilities[ id ] !== false ) {

            gl.disable( id );
            enabledCapabilities[ id ] = false;

        }

    }

bindFramebuffer(target: any, framebuffer: any): boolean

Parameters:

  • target any
  • framebuffer any

Returns: boolean

Calls:

  • gl.bindFramebuffer

Internal Comments:

// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER

Code
function bindFramebuffer( target, framebuffer ) {

        if ( currentBoundFramebuffers[ target ] !== framebuffer ) {

            gl.bindFramebuffer( target, framebuffer );

            currentBoundFramebuffers[ target ] = framebuffer;

            // gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER

            if ( target === gl.DRAW_FRAMEBUFFER ) {

                currentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;

            }

            if ( target === gl.FRAMEBUFFER ) {

                currentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;

            }

            return true;

        }

        return false;

    }

drawBuffers(renderTarget: any, framebuffer: any): void

Parameters:

  • renderTarget any
  • framebuffer any

Returns: void

Calls:

  • currentDrawbuffers.get
  • currentDrawbuffers.set
  • gl.drawBuffers
Code
function drawBuffers( renderTarget, framebuffer ) {

        let drawBuffers = defaultDrawbuffers;

        let needsUpdate = false;

        if ( renderTarget ) {

            drawBuffers = currentDrawbuffers.get( framebuffer );

            if ( drawBuffers === undefined ) {

                drawBuffers = [];
                currentDrawbuffers.set( framebuffer, drawBuffers );

            }

            const textures = renderTarget.textures;

            if ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {

                for ( let i = 0, il = textures.length; i < il; i ++ ) {

                    drawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;

                }

                drawBuffers.length = textures.length;

                needsUpdate = true;

            }

        } else {

            if ( drawBuffers[ 0 ] !== gl.BACK ) {

                drawBuffers[ 0 ] = gl.BACK;

                needsUpdate = true;

            }

        }

        if ( needsUpdate ) {

            gl.drawBuffers( drawBuffers );

        }

    }

useProgram(program: any): boolean

Parameters:

  • program any

Returns: boolean

Calls:

  • gl.useProgram
Code
function useProgram( program ) {

        if ( currentProgram !== program ) {

            gl.useProgram( program );

            currentProgram = program;

            return true;

        }

        return false;

    }

setBlending(blending: any, blendEquation: any, blendSrc: any, blendDst: any, blendEquationAlpha: any, blendSrcAlpha: any, blendDstAlpha: any, blendColor: any, blendAlpha: any, premultipliedAlpha: any): void

Parameters:

  • blending any
  • blendEquation any
  • blendSrc any
  • blendDst any
  • blendEquationAlpha any
  • blendSrcAlpha any
  • blendDstAlpha any
  • blendColor any
  • blendAlpha any
  • premultipliedAlpha any

Returns: void

Calls:

  • disable
  • enable
  • gl.blendEquation
  • gl.blendFuncSeparate
  • gl.blendFunc
  • console.error
  • currentBlendColor.set
  • gl.blendEquationSeparate
  • blendColor.equals
  • gl.blendColor
  • currentBlendColor.copy

Internal Comments:

// custom blending (x3)

Code
function setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {

        if ( blending === NoBlending ) {

            if ( currentBlendingEnabled === true ) {

                disable( gl.BLEND );
                currentBlendingEnabled = false;

            }

            return;

        }

        if ( currentBlendingEnabled === false ) {

            enable( gl.BLEND );
            currentBlendingEnabled = true;

        }

        if ( blending !== CustomBlending ) {

            if ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {

                if ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {

                    gl.blendEquation( gl.FUNC_ADD );

                    currentBlendEquation = AddEquation;
                    currentBlendEquationAlpha = AddEquation;

                }

                if ( premultipliedAlpha ) {

                    switch ( blending ) {

                        case NormalBlending:
                            gl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
                            break;

                        case AdditiveBlending:
                            gl.blendFunc( gl.ONE, gl.ONE );
                            break;

                        case SubtractiveBlending:
                            gl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );
                            break;

                        case MultiplyBlending:
                            gl.blendFuncSeparate( gl.DST_COLOR, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE );
                            break;

                        default:
                            console.error( 'THREE.WebGLState: Invalid blending: ', blending );
                            break;

                    }

                } else {

                    switch ( blending ) {

                        case NormalBlending:
                            gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );
                            break;

                        case AdditiveBlending:
                            gl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE, gl.ONE, gl.ONE );
                            break;

                        case SubtractiveBlending:
                            console.error( 'THREE.WebGLState: SubtractiveBlending requires material.premultipliedAlpha = true' );
                            break;

                        case MultiplyBlending:
                            console.error( 'THREE.WebGLState: MultiplyBlending requires material.premultipliedAlpha = true' );
                            break;

                        default:
                            console.error( 'THREE.WebGLState: Invalid blending: ', blending );
                            break;

                    }

                }

                currentBlendSrc = null;
                currentBlendDst = null;
                currentBlendSrcAlpha = null;
                currentBlendDstAlpha = null;
                currentBlendColor.set( 0, 0, 0 );
                currentBlendAlpha = 0;

                currentBlending = blending;
                currentPremultipledAlpha = premultipliedAlpha;

            }

            return;

        }

        // custom blending

        blendEquationAlpha = blendEquationAlpha || blendEquation;
        blendSrcAlpha = blendSrcAlpha || blendSrc;
        blendDstAlpha = blendDstAlpha || blendDst;

        if ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {

            gl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );

            currentBlendEquation = blendEquation;
            currentBlendEquationAlpha = blendEquationAlpha;

        }

        if ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {

            gl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );

            currentBlendSrc = blendSrc;
            currentBlendDst = blendDst;
            currentBlendSrcAlpha = blendSrcAlpha;
            currentBlendDstAlpha = blendDstAlpha;

        }

        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;

    }

setMaterial(material: any, frontFaceCW: any): void

Parameters:

  • material any
  • frontFaceCW any

Returns: void

Calls:

  • disable
  • enable
  • setFlipSided
  • setBlending
  • depthBuffer.setFunc
  • depthBuffer.setTest
  • depthBuffer.setMask
  • colorBuffer.setMask
  • stencilBuffer.setTest
  • stencilBuffer.setMask
  • stencilBuffer.setFunc
  • stencilBuffer.setOp
  • setPolygonOffset
Code
function setMaterial( material, frontFaceCW ) {

        material.side === DoubleSide
            ? disable( gl.CULL_FACE )
            : enable( gl.CULL_FACE );

        let flipSided = ( material.side === BackSide );
        if ( frontFaceCW ) flipSided = ! flipSided;

        setFlipSided( flipSided );

        ( material.blending === NormalBlending && material.transparent === false )
            ? setBlending( NoBlending )
            : 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 );
        depthBuffer.setMask( material.depthWrite );
        colorBuffer.setMask( material.colorWrite );

        const stencilWrite = material.stencilWrite;
        stencilBuffer.setTest( stencilWrite );
        if ( stencilWrite ) {

            stencilBuffer.setMask( material.stencilWriteMask );
            stencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );
            stencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );

        }

        setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );

        material.alphaToCoverage === true
            ? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )
            : disable( gl.SAMPLE_ALPHA_TO_COVERAGE );

    }

setFlipSided(flipSided: any): void

Parameters:

  • flipSided any

Returns: void

Calls:

  • gl.frontFace
Code
function setFlipSided( flipSided ) {

        if ( currentFlipSided !== flipSided ) {

            if ( flipSided ) {

                gl.frontFace( gl.CW );

            } else {

                gl.frontFace( gl.CCW );

            }

            currentFlipSided = flipSided;

        }

    }

setCullFace(cullFace: any): void

Parameters:

  • cullFace any

Returns: void

Calls:

  • enable
  • gl.cullFace
  • disable
Code
function setCullFace( cullFace ) {

        if ( cullFace !== CullFaceNone ) {

            enable( gl.CULL_FACE );

            if ( cullFace !== currentCullFace ) {

                if ( cullFace === CullFaceBack ) {

                    gl.cullFace( gl.BACK );

                } else if ( cullFace === CullFaceFront ) {

                    gl.cullFace( gl.FRONT );

                } else {

                    gl.cullFace( gl.FRONT_AND_BACK );

                }

            }

        } else {

            disable( gl.CULL_FACE );

        }

        currentCullFace = cullFace;

    }

setLineWidth(width: any): void

Parameters:

  • width any

Returns: void

Calls:

  • gl.lineWidth
Code
function setLineWidth( width ) {

        if ( width !== currentLineWidth ) {

            if ( lineWidthAvailable ) gl.lineWidth( width );

            currentLineWidth = width;

        }

    }

setPolygonOffset(polygonOffset: any, factor: any, units: any): void

Parameters:

  • polygonOffset any
  • factor any
  • units any

Returns: void

Calls:

  • enable
  • gl.polygonOffset
  • disable
Code
function setPolygonOffset( polygonOffset, factor, units ) {

        if ( polygonOffset ) {

            enable( gl.POLYGON_OFFSET_FILL );

            if ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {

                gl.polygonOffset( factor, units );

                currentPolygonOffsetFactor = factor;
                currentPolygonOffsetUnits = units;

            }

        } else {

            disable( gl.POLYGON_OFFSET_FILL );

        }

    }

setScissorTest(scissorTest: any): void

Parameters:

  • scissorTest any

Returns: void

Calls:

  • enable
  • disable
Code
function setScissorTest( scissorTest ) {

        if ( scissorTest ) {

            enable( gl.SCISSOR_TEST );

        } else {

            disable( gl.SCISSOR_TEST );

        }

    }

activeTexture(webglSlot: any): void

Parameters:

  • webglSlot any

Returns: void

Calls:

  • gl.activeTexture
Code
function activeTexture( webglSlot ) {

        if ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;

        if ( currentTextureSlot !== webglSlot ) {

            gl.activeTexture( webglSlot );
            currentTextureSlot = webglSlot;

        }

    }

bindTexture(webglType: any, webglTexture: any, webglSlot: any): void

Parameters:

  • webglType any
  • webglTexture any
  • webglSlot any

Returns: void

Calls:

  • gl.activeTexture
  • gl.bindTexture
Code
function bindTexture( webglType, webglTexture, webglSlot ) {

        if ( webglSlot === undefined ) {

            if ( currentTextureSlot === null ) {

                webglSlot = gl.TEXTURE0 + maxTextures - 1;

            } else {

                webglSlot = currentTextureSlot;

            }

        }

        let boundTexture = currentBoundTextures[ webglSlot ];

        if ( boundTexture === undefined ) {

            boundTexture = { type: undefined, texture: undefined };
            currentBoundTextures[ webglSlot ] = boundTexture;

        }

        if ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {

            if ( currentTextureSlot !== webglSlot ) {

                gl.activeTexture( webglSlot );
                currentTextureSlot = webglSlot;

            }

            gl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );

            boundTexture.type = webglType;
            boundTexture.texture = webglTexture;

        }

    }

unbindTexture(): void

Returns: void

Calls:

  • gl.bindTexture
Code
function unbindTexture() {

        const boundTexture = currentBoundTextures[ currentTextureSlot ];

        if ( boundTexture !== undefined && boundTexture.type !== undefined ) {

            gl.bindTexture( boundTexture.type, null );

            boundTexture.type = undefined;
            boundTexture.texture = undefined;

        }

    }

compressedTexImage2D(): void

Returns: void

Calls:

  • gl.compressedTexImage2D
  • console.error
Code
function compressedTexImage2D() {

        try {

            gl.compressedTexImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

compressedTexImage3D(): void

Returns: void

Calls:

  • gl.compressedTexImage3D
  • console.error
Code
function compressedTexImage3D() {

        try {

            gl.compressedTexImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texSubImage2D(): void

Returns: void

Calls:

  • gl.texSubImage2D
  • console.error
Code
function texSubImage2D() {

        try {

            gl.texSubImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texSubImage3D(): void

Returns: void

Calls:

  • gl.texSubImage3D
  • console.error
Code
function texSubImage3D() {

        try {

            gl.texSubImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

compressedTexSubImage2D(): void

Returns: void

Calls:

  • gl.compressedTexSubImage2D
  • console.error
Code
function compressedTexSubImage2D() {

        try {

            gl.compressedTexSubImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

compressedTexSubImage3D(): void

Returns: void

Calls:

  • gl.compressedTexSubImage3D
  • console.error
Code
function compressedTexSubImage3D() {

        try {

            gl.compressedTexSubImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texStorage2D(): void

Returns: void

Calls:

  • gl.texStorage2D
  • console.error
Code
function texStorage2D() {

        try {

            gl.texStorage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texStorage3D(): void

Returns: void

Calls:

  • gl.texStorage3D
  • console.error
Code
function texStorage3D() {

        try {

            gl.texStorage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texImage2D(): void

Returns: void

Calls:

  • gl.texImage2D
  • console.error
Code
function texImage2D() {

        try {

            gl.texImage2D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

texImage3D(): void

Returns: void

Calls:

  • gl.texImage3D
  • console.error
Code
function texImage3D() {

        try {

            gl.texImage3D( ...arguments );

        } catch ( error ) {

            console.error( 'THREE.WebGLState:', error );

        }

    }

scissor(scissor: any): void

Parameters:

  • scissor any

Returns: void

Calls:

  • currentScissor.equals
  • gl.scissor
  • currentScissor.copy
Code
function scissor( scissor ) {

        if ( currentScissor.equals( scissor ) === false ) {

            gl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );
            currentScissor.copy( scissor );

        }

    }

viewport(viewport: any): void

Parameters:

  • viewport any

Returns: void

Calls:

  • currentViewport.equals
  • gl.viewport
  • currentViewport.copy
Code
function viewport( viewport ) {

        if ( currentViewport.equals( viewport ) === false ) {

            gl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );
            currentViewport.copy( viewport );

        }

    }

updateUBOMapping(uniformsGroup: any, program: any): void

Parameters:

  • uniformsGroup any
  • program any

Returns: void

Calls:

  • uboProgramMap.get
  • uboProgramMap.set
  • mapping.get
  • gl.getUniformBlockIndex
  • mapping.set
Code
function updateUBOMapping( uniformsGroup, program ) {

        let mapping = uboProgramMap.get( program );

        if ( mapping === undefined ) {

            mapping = new WeakMap();

            uboProgramMap.set( program, mapping );

        }

        let blockIndex = mapping.get( uniformsGroup );

        if ( blockIndex === undefined ) {

            blockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );

            mapping.set( uniformsGroup, blockIndex );

        }

    }

uniformBlockBinding(uniformsGroup: any, program: any): void

Parameters:

  • uniformsGroup any
  • program any

Returns: void

Calls:

  • uboProgramMap.get
  • mapping.get
  • uboBindings.get
  • gl.uniformBlockBinding
  • uboBindings.set

Internal Comments:

// bind shader specific block index to global block point (x4)

Code
function uniformBlockBinding( uniformsGroup, program ) {

        const mapping = uboProgramMap.get( program );
        const blockIndex = mapping.get( uniformsGroup );

        if ( uboBindings.get( program ) !== blockIndex ) {

            // bind shader specific block index to global block point
            gl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );

            uboBindings.set( program, blockIndex );

        }

    }

reset(): void

Returns: void

Calls:

  • gl.disable
  • gl.blendEquation
  • gl.blendFunc
  • gl.blendFuncSeparate
  • gl.blendColor
  • gl.colorMask
  • gl.clearColor
  • gl.depthMask
  • gl.depthFunc
  • depthBuffer.setReversed
  • gl.clearDepth
  • gl.stencilMask
  • gl.stencilFunc
  • gl.stencilOp
  • gl.clearStencil
  • gl.cullFace
  • gl.frontFace
  • gl.polygonOffset
  • gl.activeTexture
  • gl.bindFramebuffer
  • gl.useProgram
  • gl.lineWidth
  • gl.scissor
  • gl.viewport
  • currentScissor.set
  • currentViewport.set
  • colorBuffer.reset
  • depthBuffer.reset
  • stencilBuffer.reset

Internal Comments:

// reset state (x4)
// reset internals (x3)

Code
function reset() {

        // reset state

        gl.disable( gl.BLEND );
        gl.disable( gl.CULL_FACE );
        gl.disable( gl.DEPTH_TEST );
        gl.disable( gl.POLYGON_OFFSET_FILL );
        gl.disable( gl.SCISSOR_TEST );
        gl.disable( gl.STENCIL_TEST );
        gl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );

        gl.blendEquation( gl.FUNC_ADD );
        gl.blendFunc( gl.ONE, gl.ZERO );
        gl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );
        gl.blendColor( 0, 0, 0, 0 );

        gl.colorMask( true, true, true, true );
        gl.clearColor( 0, 0, 0, 0 );

        gl.depthMask( true );
        gl.depthFunc( gl.LESS );

        depthBuffer.setReversed( false );

        gl.clearDepth( 1 );

        gl.stencilMask( 0xffffffff );
        gl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );
        gl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );
        gl.clearStencil( 0 );

        gl.cullFace( gl.BACK );
        gl.frontFace( gl.CCW );

        gl.polygonOffset( 0, 0 );

        gl.activeTexture( gl.TEXTURE0 );

        gl.bindFramebuffer( gl.FRAMEBUFFER, null );
        gl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );
        gl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );

        gl.useProgram( null );

        gl.lineWidth( 1 );

        gl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );
        gl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );

        // reset internals

        enabledCapabilities = {};

        currentTextureSlot = null;
        currentBoundTextures = {};

        currentBoundFramebuffers = {};
        currentDrawbuffers = new WeakMap();
        defaultDrawbuffers = [];

        currentProgram = null;

        currentBlendingEnabled = false;
        currentBlending = null;
        currentBlendEquation = null;
        currentBlendSrc = null;
        currentBlendDst = null;
        currentBlendEquationAlpha = null;
        currentBlendSrcAlpha = null;
        currentBlendDstAlpha = null;
        currentBlendColor = new Color( 0, 0, 0 );
        currentBlendAlpha = 0;
        currentPremultipledAlpha = false;

        currentFlipSided = null;
        currentCullFace = null;

        currentLineWidth = null;

        currentPolygonOffsetFactor = null;
        currentPolygonOffsetUnits = null;

        currentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );
        currentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );

        colorBuffer.reset();
        depthBuffer.reset();
        stencilBuffer.reset();

    }

WebGLTextures(_gl: any, extensions: any, state: any, properties: any, capabilities: any, utils: any, info: any): void

Parameters:

  • _gl any
  • extensions any
  • state any
  • properties any
  • capabilities any
  • utils any
  • info any

Returns: void

Calls:

  • extensions.has
  • extensions.get
  • /OculusBrowser/g.test
  • new OffscreenCanvas( 1, 1 ).getContext
  • createElementNS (from ./three.core.js)
  • getDimensions
  • Math.max
  • Math.floor
  • createCanvas
  • canvas.getContext
  • context.drawImage
  • console.warn
  • _gl.generateMipmap
  • ColorManagement.getTransfer
  • textureNeedsGenerateMipmaps
  • Math.log2
  • Array.isArray
  • texture.removeEventListener
  • deallocateTexture
  • _videoTextures.delete
  • renderTarget.removeEventListener
  • deallocateRenderTarget
  • properties.get
  • _sources.get
  • deleteTexture
  • Object.keys
  • _sources.delete
  • properties.remove
  • _gl.deleteTexture
  • renderTarget.depthTexture.dispose
  • _gl.deleteFramebuffer
  • _gl.deleteRenderbuffer
  • array.push
  • array.join
  • updateVideoTexture
  • uploadTexture
  • state.bindTexture
  • uploadCubeTexture
  • _gl.texParameteri
  • _gl.texParameterf
  • Math.min
  • capabilities.getMaxAnisotropy
  • texture.addEventListener
  • _sources.set
  • getTextureCacheKey
  • _gl.createTexture
  • state.texSubImage2D
  • updateRanges.sort
  • getRow
  • _gl.getParameter
  • _gl.pixelStorei
  • Math.ceil
  • texture.clearUpdateRanges
  • initTexture
  • state.activeTexture
  • ColorManagement.getPrimaries
  • resizeImage
  • verifyColorSpace
  • utils.convert
  • getInternalFormat
  • setTextureParameters
  • getMipLevels
  • getInternalDepthFormat
  • state.texStorage2D
  • state.texImage2D
  • updateTexture
  • state.texStorage3D
  • getByteLength (from ./three.core.js)
  • mipmap.data.subarray
  • state.compressedTexSubImage3D
  • texture.clearLayerUpdates
  • state.compressedTexImage3D
  • state.texSubImage3D
  • state.texImage3D
  • state.compressedTexSubImage2D
  • state.compressedTexImage2D
  • image.data.subarray
  • generateMipmap
  • texture.onUpdate
  • state.bindFramebuffer
  • useMultisampledRTT
  • multisampledRTTExt.framebufferTexture2DMultisampleEXT
  • getRenderTargetSamples
  • _gl.framebufferTexture2D
  • _gl.bindRenderbuffer
  • multisampledRTTExt.renderbufferStorageMultisampleEXT
  • _gl.renderbufferStorageMultisample
  • _gl.renderbufferStorage
  • _gl.framebufferRenderbuffer
  • setTexture2D
  • renderTargetProperties.__depthDisposeCallback
  • depthTexture.removeEventListener
  • depthTexture.addEventListener
  • setupDepthTexture
  • _gl.createRenderbuffer
  • setupRenderBufferStorage
  • setupFrameBufferTexture
  • setupDepthRenderbuffer
  • renderTarget.addEventListener
  • _gl.createFramebuffer
  • state.unbindTexture
  • getTargetType
  • _gl.blitFramebuffer
  • invalidationArrayRead.push
  • invalidationArrayDraw.push
  • _gl.invalidateFramebuffer
  • _videoTextures.get
  • _videoTextures.set
  • texture.update
  • console.error

Internal Comments:

// cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas, (x2)
// also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")! (x2)
// Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d). (x2)
// eslint-disable-next-line compat/compat (x2)
// Use OffscreenCanvas when available. Specially needed in web workers
// handle case if texture exceeds max size
// only perform resize if necessary
// only perform resize for certain image types
// cube textures can't reuse the same canvas (x2)
// user-defined mipmaps
// texture without mipmaps (only base level)
// (x14)
// check if it's necessary to remove the WebGLTexture object (x2)
// the WebGLTexture object is not used anymore, remove it
// remove the weak map entry if no WebGLTexture uses the source anymore
// create Source <-> WebGLTextures mapping if necessary (x2)
// check if there is already a WebGLTexture object for the given texture parameters (x2)
// if not, create a new instance of WebGLTexture
// create new entry (x4)
// when a new instance of WebGLTexture was created, a texture upload is required (x3)
// even if the image contents are identical (x3)
// every time the texture cache key changes, it's necessary to check if an instance of (x2)
// WebGLTexture can be deleted in order to avoid a memory leak. (x2)
// store references to cache key and WebGLTexture object (x4)
// Before applying update ranges, we merge any adjacent / overlapping (x4)
// ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led (x4)
// to performance improvements for applications which make heavy use of (x4)
// update ranges. Likely due to GPU command overhead. (x4)
// Note that to reduce garbage collection between frames, we merge the (x4)
// update ranges in-place. This is safe because this method will clear the (x4)
// update ranges once updated. (x4)
// To merge the update ranges in-place, we work from left to right in the (x2)
// existing updateRanges array, merging ranges. This may result in a final (x2)
// array which is smaller than the original. This index tracks the last (x2)
// index representing a merged range, any data after this index can be (x2)
// trimmed once the merge algorithm is completed. (x2)
// Only merge if in the same row and overlapping/adjacent (x2)
// We add one here to merge adjacent ranges. This is safe because ranges
// operate over positive integers.
// Trim the array to only contain the merged ranges. (x4)
// Assumes update ranges refer to contiguous memory (x2)
// use manually created mipmaps if available (x2)
// if there are no manual mipmaps (x2)
// set 0 level mipmap and then use GL to generate other mipmap levels (x2)
// regular Texture (image, video, canvas)
// TODO: Uniformly handle mipmap definitions
// Normal textures and compressed cube textures define base level + mips with their mipmap array
// Uncompressed cube textures use their mipmap array only for mips (no base level)
// We assume images for cube map have the same size. (x3)
// Render targets
// Setup storage for target texture and bind it to correct framebuffer
// Setup storage for internal depth/stencil buffers and bind to correct framebuffer
// retrieve the depth attachment types (x2)
// set up the attachment (x2)
// Setup resources for a Depth Texture for a FBO (needs an extension)
// upload an empty depth texture with framebuffer size
// Setup GL resources for a non-texture depth buffer
// if the bound depth texture has changed
// fire the dispose event to get rid of stored state associated with the previously bound depth buffer (x2)
// set up dispose listeners to track when the currently attached buffer is implicitly unbound
// attach buffer if it's been created already (x4)
// rebind framebuffer with external textures
// Set up GL resources for the render target
// Setup framebuffer
// Setup color buffer
// Setup depth and stencil buffers
// If MRT we need to remove FBO attachments
// resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)
// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments
// Check the last frame we updated the VideoTexture
// sRGB
// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format
// if intrinsic data are not available, fallback to width/height (x4)

Code
function WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {

    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 );

    const _imageDimensions = new Vector2();
    const _videoTextures = new WeakMap();
    let _canvas;

    const _sources = new WeakMap(); // maps WebglTexture objects to instances of Source

    // cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,
    // also OffscreenCanvas.getContext("webgl"), but not OffscreenCanvas.getContext("2d")!
    // Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).

    let useOffscreenCanvas = false;

    try {

        useOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'
            // eslint-disable-next-line compat/compat
            && ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;

    } catch ( err ) {

        // Ignore any errors

    }

    function createCanvas( width, height ) {

        // Use OffscreenCanvas when available. Specially needed in web workers

        return useOffscreenCanvas ?
            // eslint-disable-next-line compat/compat
            new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );

    }

    function resizeImage( image, needsNewCanvas, maxSize ) {

        let scale = 1;

        const dimensions = getDimensions( image );

        // handle case if texture exceeds max size

        if ( dimensions.width > maxSize || dimensions.height > maxSize ) {

            scale = maxSize / Math.max( dimensions.width, dimensions.height );

        }

        // only perform resize if necessary

        if ( scale < 1 ) {

            // only perform resize for certain image types

            if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
                ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
                ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ||
                ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) ) {

                const width = Math.floor( scale * dimensions.width );
                const height = Math.floor( scale * dimensions.height );

                if ( _canvas === undefined ) _canvas = createCanvas( width, height );

                // cube textures can't reuse the same canvas

                const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;

                canvas.width = width;
                canvas.height = height;

                const context = canvas.getContext( '2d' );
                context.drawImage( image, 0, 0, width, height );

                console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').' );

                return canvas;

            } else {

                if ( 'data' in image ) {

                    console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').' );

                }

                return image;

            }

        }

        return image;

    }

    function textureNeedsGenerateMipmaps( texture ) {

        return texture.generateMipmaps;

    }

    function generateMipmap( target ) {

        _gl.generateMipmap( target );

    }

    function getTargetType( texture ) {

        if ( texture.isWebGLCubeRenderTarget ) return _gl.TEXTURE_CUBE_MAP;
        if ( texture.isWebGL3DRenderTarget ) return _gl.TEXTURE_3D;
        if ( texture.isWebGLArrayRenderTarget || texture.isCompressedArrayTexture ) return _gl.TEXTURE_2D_ARRAY;
        return _gl.TEXTURE_2D;

    }

    function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {

        if ( internalFormatName !== null ) {

            if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];

            console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );

        }

        let internalFormat = glFormat;

        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 === _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 === _gl.RG ) {

            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 === _gl.RG_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RG16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RG32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RG8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RG16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RG32I;

        }

        if ( glFormat === _gl.RGB_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RGB32I;

        }

        if ( glFormat === _gl.RGBA_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I;

        }

        if ( glFormat === _gl.RGB ) {

            if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;

        }

        if ( glFormat === _gl.RGBA ) {

            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 === _gl.R16F || internalFormat === _gl.R32F ||
            internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
            internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {

            extensions.get( 'EXT_color_buffer_float' );

        }

        return internalFormat;

    }

    function getInternalDepthFormat( useStencil, depthType ) {

        let glInternalFormat;
        if ( useStencil ) {

            if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {

                glInternalFormat = _gl.DEPTH24_STENCIL8;

            } else if ( depthType === FloatType ) {

                glInternalFormat = _gl.DEPTH32F_STENCIL8;

            } else if ( depthType === UnsignedShortType ) {

                glInternalFormat = _gl.DEPTH24_STENCIL8;
                console.warn( 'DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.' );

            }

        } else {

            if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {

                glInternalFormat = _gl.DEPTH_COMPONENT24;

            } else if ( depthType === FloatType ) {

                glInternalFormat = _gl.DEPTH_COMPONENT32F;

            } else if ( depthType === UnsignedShortType ) {

                glInternalFormat = _gl.DEPTH_COMPONENT16;

            }

        }

        return glInternalFormat;

    }

    function getMipLevels( texture, image ) {

        if ( textureNeedsGenerateMipmaps( texture ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {

            return Math.log2( Math.max( image.width, image.height ) ) + 1;

        } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {

            // user-defined mipmaps

            return texture.mipmaps.length;

        } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {

            return image.mipmaps.length;

        } else {

            // texture without mipmaps (only base level)

            return 1;

        }

    }

    //

    function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        deallocateTexture( texture );

        if ( texture.isVideoTexture ) {

            _videoTextures.delete( texture );

        }

    }

    function onRenderTargetDispose( event ) {

        const renderTarget = event.target;

        renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );

        deallocateRenderTarget( renderTarget );

    }

    //

    function deallocateTexture( texture ) {

        const textureProperties = properties.get( texture );

        if ( textureProperties.__webglInit === undefined ) return;

        // check if it's necessary to remove the WebGLTexture object

        const source = texture.source;
        const webglTextures = _sources.get( source );

        if ( webglTextures ) {

            const webglTexture = webglTextures[ textureProperties.__cacheKey ];
            webglTexture.usedTimes --;

            // the WebGLTexture object is not used anymore, remove it

            if ( webglTexture.usedTimes === 0 ) {

                deleteTexture( texture );

            }

            // remove the weak map entry if no WebGLTexture uses the source anymore

            if ( Object.keys( webglTextures ).length === 0 ) {

                _sources.delete( source );

            }

        }

        properties.remove( texture );

    }

    function deleteTexture( texture ) {

        const textureProperties = properties.get( texture );
        _gl.deleteTexture( textureProperties.__webglTexture );

        const source = texture.source;
        const webglTextures = _sources.get( source );
        delete webglTextures[ textureProperties.__cacheKey ];

        info.memory.textures --;

    }

    function deallocateRenderTarget( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );

        if ( renderTarget.depthTexture ) {

            renderTarget.depthTexture.dispose();

            properties.remove( renderTarget.depthTexture );

        }

        if ( renderTarget.isWebGLCubeRenderTarget ) {

            for ( let i = 0; i < 6; 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 {

            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 );

            if ( renderTargetProperties.__webglColorRenderbuffer ) {

                for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {

                    if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );

                }

            }

            if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );

        }

        const textures = renderTarget.textures;

        for ( let i = 0, il = textures.length; i < il; i ++ ) {

            const attachmentProperties = properties.get( textures[ i ] );

            if ( attachmentProperties.__webglTexture ) {

                _gl.deleteTexture( attachmentProperties.__webglTexture );

                info.memory.textures --;

            }

            properties.remove( textures[ i ] );

        }

        properties.remove( renderTarget );

    }

    //

    let textureUnits = 0;

    function resetTextureUnits() {

        textureUnits = 0;

    }

    function allocateTextureUnit() {

        const textureUnit = textureUnits;

        if ( textureUnit >= capabilities.maxTextures ) {

            console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );

        }

        textureUnits += 1;

        return textureUnit;

    }

    function getTextureCacheKey( texture ) {

        const array = [];

        array.push( texture.wrapS );
        array.push( texture.wrapT );
        array.push( texture.wrapR || 0 );
        array.push( texture.magFilter );
        array.push( texture.minFilter );
        array.push( texture.anisotropy );
        array.push( texture.internalFormat );
        array.push( texture.format );
        array.push( texture.type );
        array.push( texture.generateMipmaps );
        array.push( texture.premultiplyAlpha );
        array.push( texture.flipY );
        array.push( texture.unpackAlignment );
        array.push( texture.colorSpace );

        return array.join();

    }

    //

    function setTexture2D( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isVideoTexture ) updateVideoTexture( texture );

        if ( texture.isRenderTargetTexture === false && texture.isExternalTexture !== true && texture.version > 0 && textureProperties.__version !== texture.version ) {

            const image = texture.image;

            if ( image === null ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );

            } else if ( image.complete === false ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );

            } else {

                uploadTexture( textureProperties, texture, slot );
                return;

            }

        } else if ( texture.isExternalTexture ) {

            textureProperties.__webglTexture = texture.sourceTexture ? texture.sourceTexture : null;

        }

        state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

    function setTexture2DArray( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

    function setTexture3D( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

    function setTextureCube( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadCubeTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

    const wrappingToGL = {
        [ RepeatWrapping ]: _gl.REPEAT,
        [ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,
        [ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT
    };

    const filterToGL = {
        [ NearestFilter ]: _gl.NEAREST,
        [ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,
        [ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,

        [ LinearFilter ]: _gl.LINEAR,
        [ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,
        [ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR
    };

    const compareToGL = {
        [ NeverCompare ]: _gl.NEVER,
        [ AlwaysCompare ]: _gl.ALWAYS,
        [ LessCompare ]: _gl.LESS,
        [ LessEqualCompare ]: _gl.LEQUAL,
        [ EqualCompare ]: _gl.EQUAL,
        [ GreaterEqualCompare ]: _gl.GEQUAL,
        [ GreaterCompare ]: _gl.GREATER,
        [ NotEqualCompare ]: _gl.NOTEQUAL
    };

    function setTextureParameters( textureType, texture ) {

        if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false &&
            ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter ||
            texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) {

            console.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' );

        }

        _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
        _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );

        if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {

            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );

        }

        _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
        _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );

        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 ) {

            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

            if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {

                const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
                _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
                properties.get( texture ).__currentAnisotropy = texture.anisotropy;

            }

        }

    }

    function initTexture( textureProperties, texture ) {

        let forceUpload = false;

        if ( textureProperties.__webglInit === undefined ) {

            textureProperties.__webglInit = true;

            texture.addEventListener( 'dispose', onTextureDispose );

        }

        // create Source <-> WebGLTextures mapping if necessary

        const source = texture.source;
        let webglTextures = _sources.get( source );

        if ( webglTextures === undefined ) {

            webglTextures = {};
            _sources.set( source, webglTextures );

        }

        // check if there is already a WebGLTexture object for the given texture parameters

        const textureCacheKey = getTextureCacheKey( texture );

        if ( textureCacheKey !== textureProperties.__cacheKey ) {

            // if not, create a new instance of WebGLTexture

            if ( webglTextures[ textureCacheKey ] === undefined ) {

                // create new entry

                webglTextures[ textureCacheKey ] = {
                    texture: _gl.createTexture(),
                    usedTimes: 0
                };

                info.memory.textures ++;

                // when a new instance of WebGLTexture was created, a texture upload is required
                // even if the image contents are identical

                forceUpload = true;

            }

            webglTextures[ textureCacheKey ].usedTimes ++;

            // every time the texture cache key changes, it's necessary to check if an instance of
            // WebGLTexture can be deleted in order to avoid a memory leak.

            const webglTexture = webglTextures[ textureProperties.__cacheKey ];

            if ( webglTexture !== undefined ) {

                webglTextures[ textureProperties.__cacheKey ].usedTimes --;

                if ( webglTexture.usedTimes === 0 ) {

                    deleteTexture( texture );

                }

            }

            // store references to cache key and WebGLTexture object

            textureProperties.__cacheKey = textureCacheKey;
            textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;

        }

        return forceUpload;

    }

    function getRow( index, rowLength, componentStride ) {

        return Math.floor( Math.floor( index / componentStride ) / rowLength );

    }

    function updateTexture( texture, image, glFormat, glType ) {

        const componentStride = 4; // only RGBA supported

        const updateRanges = texture.updateRanges;

        if ( updateRanges.length === 0 ) {

            state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );

        } else {

            // Before applying update ranges, we merge any adjacent / overlapping
            // ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led
            // to performance improvements for applications which make heavy use of
            // update ranges. Likely due to GPU command overhead.
            //
            // Note that to reduce garbage collection between frames, we merge the
            // update ranges in-place. This is safe because this method will clear the
            // update ranges once updated.

            updateRanges.sort( ( a, b ) => a.start - b.start );

            // To merge the update ranges in-place, we work from left to right in the
            // existing updateRanges array, merging ranges. This may result in a final
            // array which is smaller than the original. This index tracks the last
            // index representing a merged range, any data after this index can be
            // trimmed once the merge algorithm is completed.
            let mergeIndex = 0;

            for ( let i = 1; i < updateRanges.length; i ++ ) {

                const previousRange = updateRanges[ mergeIndex ];
                const range = updateRanges[ i ];

                // Only merge if in the same row and overlapping/adjacent
                const previousEnd = previousRange.start + previousRange.count;
                const currentRow = getRow( range.start, image.width, componentStride );
                const previousRow = getRow( previousRange.start, image.width, componentStride );

                // We add one here to merge adjacent ranges. This is safe because ranges
                // operate over positive integers.
                if (
                    range.start <= previousEnd + 1 &&
                    currentRow === previousRow &&
                    getRow( range.start + range.count - 1, image.width, componentStride ) === currentRow // ensure range doesn't spill
                ) {

                    previousRange.count = Math.max(
                        previousRange.count,
                        range.start + range.count - previousRange.start
                    );

                } else {

                    ++ mergeIndex;
                    updateRanges[ mergeIndex ] = range;

                }


            }

            // Trim the array to only contain the merged ranges.
            updateRanges.length = mergeIndex + 1;

            const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
            const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
            const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );

            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );

            for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {

                const range = updateRanges[ i ];

                const pixelStart = Math.floor( range.start / componentStride );
                const pixelCount = Math.ceil( range.count / componentStride );

                const x = pixelStart % image.width;
                const y = Math.floor( pixelStart / image.width );

                // Assumes update ranges refer to contiguous memory
                const width = pixelCount;
                const height = 1;

                _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x );
                _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, y );

                state.texSubImage2D( _gl.TEXTURE_2D, 0, x, y, width, height, glFormat, glType, image.data );

            }

            texture.clearUpdateRanges();

            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
            _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
            _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );

        }

    }

    function uploadTexture( textureProperties, texture, slot ) {

        let textureType = _gl.TEXTURE_2D;

        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, _gl.TEXTURE0 + slot );

        const sourceProperties = properties.get( source );

        if ( source.version !== sourceProperties.__version || forceUpload === true ) {

            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( _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 );

            let image = resizeImage( texture.image, false, capabilities.maxTextureSize );
            image = verifyColorSpace( texture, image );

            const glFormat = utils.convert( texture.format, texture.colorSpace );

            const glType = utils.convert( texture.type );
            let glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );

            setTextureParameters( textureType, texture );

            let mipmap;
            const mipmaps = texture.mipmaps;

            const useTexStorage = ( texture.isVideoTexture !== true );
            const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
            const dataReady = source.dataReady;
            const levels = getMipLevels( texture, image );

            if ( texture.isDepthTexture ) {

                glInternalFormat = getInternalDepthFormat( texture.format === DepthStencilFormat, texture.type );

                //

                if ( allocateMemory ) {

                    if ( useTexStorage ) {

                        state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );

                    }

                }

            } else if ( texture.isDataTexture ) {

                // use manually created mipmaps if available
                // if there are no manual mipmaps
                // set 0 level mipmap and then use GL to generate other mipmap levels

                if ( mipmaps.length > 0 ) {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                        }

                    }

                    texture.generateMipmaps = false;

                } else {

                    if ( useTexStorage ) {

                        if ( allocateMemory ) {

                            state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );

                        }

                        if ( dataReady ) {

                            updateTexture( texture, image, glFormat, glType );

                        }

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );

                    }

                }

            } else if ( texture.isCompressedTexture ) {

                if ( texture.isCompressedArrayTexture ) {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        if ( texture.layerUpdates.size > 0 ) {

                                            const layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );

                                            for ( const layerIndex of texture.layerUpdates ) {

                                                const layerData = mipmap.data.subarray(
                                                    layerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT,
                                                    ( layerIndex + 1 ) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT
                                                );
                                                state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData );

                                            }

                                            texture.clearLayerUpdates();

                                        } else {

                                            state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data );

                                        }

                                    }

                                } else {

                                    state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                } else {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );

                                    }

                                } else {

                                    state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                }

            } else if ( texture.isDataArrayTexture ) {

                if ( useTexStorage ) {

                    if ( allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );

                    }

                    if ( dataReady ) {

                        if ( texture.layerUpdates.size > 0 ) {

                            const layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type );

                            for ( const layerIndex of texture.layerUpdates ) {

                                const layerData = image.data.subarray(
                                    layerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT,
                                    ( layerIndex + 1 ) * layerByteLength / image.data.BYTES_PER_ELEMENT
                                );
                                state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData );

                            }

                            texture.clearLayerUpdates();

                        } else {

                            state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );

                        }

                    }

                } else {

                    state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );

                }

            } else if ( texture.isData3DTexture ) {

                if ( useTexStorage ) {

                    if ( allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );

                    }

                    if ( dataReady ) {

                        state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );

                    }

                } else {

                    state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );

                }

            } else if ( texture.isFramebufferTexture ) {

                if ( allocateMemory ) {

                    if ( useTexStorage ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );

                    } else {

                        let width = image.width, height = image.height;

                        for ( let i = 0; i < levels; i ++ ) {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );

                            width >>= 1;
                            height >>= 1;

                        }

                    }

                }

            } else {

                // regular Texture (image, video, canvas)

                // use manually created mipmaps if available
                // if there are no manual mipmaps
                // set 0 level mipmap and then use GL to generate other mipmap levels

                if ( mipmaps.length > 0 ) {

                    if ( useTexStorage && allocateMemory ) {

                        const dimensions = getDimensions( mipmaps[ 0 ] );

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );

                        }

                    }

                    texture.generateMipmaps = false;

                } else {

                    if ( useTexStorage ) {

                        if ( allocateMemory ) {

                            const dimensions = getDimensions( image );

                            state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );

                        }

                        if ( dataReady ) {

                            state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );

                        }

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );

                    }

                }

            }

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                generateMipmap( textureType );

            }

            sourceProperties.__version = source.version;

            if ( texture.onUpdate ) texture.onUpdate( texture );

        }

        textureProperties.__version = texture.version;

    }

    function uploadCubeTexture( textureProperties, texture, slot ) {

        if ( texture.image.length !== 6 ) return;

        const forceUpload = initTexture( textureProperties, texture );
        const source = texture.source;

        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( _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( _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 );

            const cubeImage = [];

            for ( let i = 0; i < 6; i ++ ) {

                if ( ! isCompressed && ! isDataTexture ) {

                    cubeImage[ i ] = resizeImage( texture.image[ i ], true, capabilities.maxCubemapSize );

                } else {

                    cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];

                }

                cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );

            }

            const image = cubeImage[ 0 ],
                glFormat = utils.convert( texture.format, texture.colorSpace ),
                glType = utils.convert( texture.type ),
                glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );

            const useTexStorage = ( texture.isVideoTexture !== true );
            const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
            const dataReady = source.dataReady;
            let levels = getMipLevels( texture, image );

            setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );

            let mipmaps;

            if ( isCompressed ) {

                if ( useTexStorage && allocateMemory ) {

                    state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );

                }

                for ( let i = 0; i < 6; i ++ ) {

                    mipmaps = cubeImage[ i ].mipmaps;

                    for ( let j = 0; j < mipmaps.length; j ++ ) {

                        const mipmap = mipmaps[ j ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );

                                    }

                                } else {

                                    state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                }

            } else {

                mipmaps = texture.mipmaps;

                if ( useTexStorage && allocateMemory ) {

                    // TODO: Uniformly handle mipmap definitions
                    // Normal textures and compressed cube textures define base level + mips with their mipmap array
                    // Uncompressed cube textures use their mipmap array only for mips (no base level)

                    if ( mipmaps.length > 0 ) levels ++;

                    const dimensions = getDimensions( cubeImage[ 0 ] );

                    state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height );

                }

                for ( let i = 0; i < 6; i ++ ) {

                    if ( isDataTexture ) {

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                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( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );

                        }

                        for ( let j = 0; j < mipmaps.length; j ++ ) {

                            const mipmap = mipmaps[ j ];
                            const mipmapImage = mipmap.image[ i ].image;

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );

                            }

                        }

                    } else {

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );

                        }

                        for ( let j = 0; j < mipmaps.length; j ++ ) {

                            const mipmap = mipmaps[ j ];

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );

                            }

                        }

                    }

                }

            }

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                // We assume images for cube map have the same size.
                generateMipmap( _gl.TEXTURE_CUBE_MAP );

            }

            sourceProperties.__version = source.version;

            if ( texture.onUpdate ) texture.onUpdate( texture );

        }

        textureProperties.__version = texture.version;

    }

    // Render targets

    // Setup storage for target texture and bind it to correct framebuffer
    function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {

        const glFormat = utils.convert( texture.format, texture.colorSpace );
        const glType = utils.convert( texture.type );
        const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
        const renderTargetProperties = properties.get( renderTarget );
        const textureProperties = properties.get( texture );

        textureProperties.__renderTarget = renderTarget;

        if ( ! renderTargetProperties.__hasExternalTextures ) {

            const width = Math.max( 1, renderTarget.width >> level );
            const height = Math.max( 1, renderTarget.height >> level );

            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, level, glInternalFormat, width, height, 0, glFormat, glType, null );

            }

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

        if ( useMultisampledRTT( renderTarget ) ) {

            multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, 0, getRenderTargetSamples( renderTarget ) );

        } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753

            _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, level );

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

    // Setup storage for internal depth/stencil buffers and bind to correct framebuffer
    function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );

        if ( renderTarget.depthBuffer ) {

            // retrieve the depth attachment types
            const depthTexture = renderTarget.depthTexture;
            const depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null;
            const glInternalFormat = getInternalDepthFormat( renderTarget.stencilBuffer, depthType );
            const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;

            // set up the attachment
            const samples = getRenderTargetSamples( renderTarget );
            const isUseMultisampledRTT = useMultisampledRTT( renderTarget );
            if ( isUseMultisampledRTT ) {

                multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

            } else if ( isMultisample ) {

                _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

            } else {

                _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );

            }

            _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

        } else {

            const textures = renderTarget.textures;

            for ( let i = 0; i < textures.length; i ++ ) {

                const texture = textures[ i ];

                const glFormat = utils.convert( texture.format, texture.colorSpace );
                const glType = utils.convert( texture.type );
                const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
                const samples = getRenderTargetSamples( renderTarget );

                if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {

                    _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                } else if ( useMultisampledRTT( renderTarget ) ) {

                    multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                } else {

                    _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );

                }

            }

        }

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

    }

    // Setup resources for a Depth Texture for a FBO (needs an extension)
    function setupDepthTexture( framebuffer, renderTarget ) {

        const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
        if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );

        state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

        if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {

            throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );

        }

        const textureProperties = properties.get( renderTarget.depthTexture );
        textureProperties.__renderTarget = renderTarget;

        // upload an empty depth texture with framebuffer size
        if ( ! textureProperties.__webglTexture ||
                renderTarget.depthTexture.image.width !== renderTarget.width ||
                renderTarget.depthTexture.image.height !== renderTarget.height ) {

            renderTarget.depthTexture.image.width = renderTarget.width;
            renderTarget.depthTexture.image.height = renderTarget.height;
            renderTarget.depthTexture.needsUpdate = true;

        }

        setTexture2D( renderTarget.depthTexture, 0 );

        const webglDepthTexture = textureProperties.__webglTexture;
        const samples = getRenderTargetSamples( renderTarget );

        if ( renderTarget.depthTexture.format === DepthFormat ) {

            if ( useMultisampledRTT( renderTarget ) ) {

                multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );

            } else {

                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

            }

        } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {

            if ( useMultisampledRTT( renderTarget ) ) {

                multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );

            } else {

                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

            }

        } else {

            throw new Error( 'Unknown depthTexture format' );

        }

    }

    // Setup GL resources for a non-texture depth buffer
    function setupDepthRenderbuffer( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );
        const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );

        // if the bound depth texture has changed
        if ( renderTargetProperties.__boundDepthTexture !== renderTarget.depthTexture ) {

            // fire the dispose event to get rid of stored state associated with the previously bound depth buffer
            const depthTexture = renderTarget.depthTexture;
            if ( renderTargetProperties.__depthDisposeCallback ) {

                renderTargetProperties.__depthDisposeCallback();

            }

            // set up dispose listeners to track when the currently attached buffer is implicitly unbound
            if ( depthTexture ) {

                const disposeEvent = () => {

                    delete renderTargetProperties.__boundDepthTexture;
                    delete renderTargetProperties.__depthDisposeCallback;
                    depthTexture.removeEventListener( 'dispose', disposeEvent );

                };

                depthTexture.addEventListener( 'dispose', disposeEvent );
                renderTargetProperties.__depthDisposeCallback = disposeEvent;

            }

            renderTargetProperties.__boundDepthTexture = depthTexture;

        }

        if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {

            if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );

            const mipmaps = renderTarget.texture.mipmaps;

            if ( mipmaps && mipmaps.length > 0 ) {

                setupDepthTexture( renderTargetProperties.__webglFramebuffer[ 0 ], renderTarget );

            } else {

                setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );

            }

        } else {

            if ( isCube ) {

                renderTargetProperties.__webglDepthbuffer = [];

                for ( let i = 0; i < 6; i ++ ) {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );

                    if ( renderTargetProperties.__webglDepthbuffer[ i ] === undefined ) {

                        renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
                        setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );

                    } else {

                        // attach buffer if it's been created already
                        const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                        const renderbuffer = renderTargetProperties.__webglDepthbuffer[ i ];
                        _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

                    }

                }

            } else {

                const mipmaps = renderTarget.texture.mipmaps;

                if ( mipmaps && mipmaps.length > 0 ) {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] );

                } else {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );

                }

                if ( renderTargetProperties.__webglDepthbuffer === undefined ) {

                    renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
                    setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );

                } else {

                    // attach buffer if it's been created already
                    const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                    const renderbuffer = renderTargetProperties.__webglDepthbuffer;
                    _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
                    _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

                }

            }

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

    // rebind framebuffer with external textures
    function rebindTextures( renderTarget, colorTexture, depthTexture ) {

        const renderTargetProperties = properties.get( renderTarget );

        if ( colorTexture !== undefined ) {

            setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );

        }

        if ( depthTexture !== undefined ) {

            setupDepthRenderbuffer( renderTarget );

        }

    }

    // Set up GL resources for the render target
    function setupRenderTarget( renderTarget ) {

        const texture = renderTarget.texture;

        const renderTargetProperties = properties.get( renderTarget );
        const textureProperties = properties.get( texture );

        renderTarget.addEventListener( 'dispose', onRenderTargetDispose );

        const textures = renderTarget.textures;

        const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
        const isMultipleRenderTargets = ( textures.length > 1 );

        if ( ! isMultipleRenderTargets ) {

            if ( textureProperties.__webglTexture === undefined ) {

                textureProperties.__webglTexture = _gl.createTexture();

            }

            textureProperties.__version = texture.version;
            info.memory.textures ++;

        }

        // Setup framebuffer

        if ( isCube ) {

            renderTargetProperties.__webglFramebuffer = [];

            for ( let i = 0; i < 6; i ++ ) {

                if ( 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 {

            if ( 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 ) {

                for ( let i = 0, il = textures.length; i < il; i ++ ) {

                    const attachmentProperties = properties.get( textures[ i ] );

                    if ( attachmentProperties.__webglTexture === undefined ) {

                        attachmentProperties.__webglTexture = _gl.createTexture();

                        info.memory.textures ++;

                    }

                }

            }

            if ( ( renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {

                renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
                renderTargetProperties.__webglColorRenderbuffer = [];

                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( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                    const glFormat = utils.convert( texture.format, texture.colorSpace );
                    const glType = utils.convert( texture.type );
                    const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
                    const samples = getRenderTargetSamples( renderTarget );
                    _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                    _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                }

                _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

                if ( renderTarget.depthBuffer ) {

                    renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
                    setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );

                }

                state.bindFramebuffer( _gl.FRAMEBUFFER, null );

            }

        }

        // Setup color buffer

        if ( isCube ) {

            state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
            setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );

            for ( let i = 0; i < 6; i ++ ) {

                if ( 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 ) ) {

                generateMipmap( _gl.TEXTURE_CUBE_MAP );

            }

            state.unbindTexture();

        } else if ( isMultipleRenderTargets ) {

            for ( let i = 0, il = textures.length; i < il; i ++ ) {

                const attachment = textures[ i ];
                const attachmentProperties = properties.get( attachment );

                let glTextureType = _gl.TEXTURE_2D;

                if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {

                    glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;

                }

                state.bindTexture( glTextureType, attachmentProperties.__webglTexture );
                setTextureParameters( glTextureType, attachment );
                setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, glTextureType, 0 );

                if ( textureNeedsGenerateMipmaps( attachment ) ) {

                    generateMipmap( glTextureType );

                }

            }

            state.unbindTexture();

        } else {

            let glTextureType = _gl.TEXTURE_2D;

            if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {

                glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;

            }

            state.bindTexture( glTextureType, textureProperties.__webglTexture );
            setTextureParameters( glTextureType, texture );

            if ( 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 ) ) {

                generateMipmap( glTextureType );

            }

            state.unbindTexture();

        }

        // Setup depth and stencil buffers

        if ( renderTarget.depthBuffer ) {

            setupDepthRenderbuffer( renderTarget );

        }

    }

    function updateRenderTargetMipmap( renderTarget ) {

        const textures = renderTarget.textures;

        for ( let i = 0, il = textures.length; i < il; i ++ ) {

            const texture = textures[ i ];

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                const targetType = getTargetType( renderTarget );
                const webglTexture = properties.get( texture ).__webglTexture;

                state.bindTexture( targetType, webglTexture );
                generateMipmap( targetType );
                state.unbindTexture();

            }

        }

    }

    const invalidationArrayRead = [];
    const invalidationArrayDraw = [];

    function updateMultisampleRenderTarget( renderTarget ) {

        if ( renderTarget.samples > 0 ) {

            if ( useMultisampledRTT( renderTarget ) === false ) {

                const textures = renderTarget.textures;
                const width = renderTarget.width;
                const height = renderTarget.height;
                let mask = _gl.COLOR_BUFFER_BIT;
                const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                const renderTargetProperties = properties.get( renderTarget );
                const isMultipleRenderTargets = ( textures.length > 1 );

                // If MRT we need to remove FBO attachments
                if ( isMultipleRenderTargets ) {

                    for ( let i = 0; i < textures.length; i ++ ) {

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );

                    }

                }

                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );

                const mipmaps = renderTarget.texture.mipmaps;

                if ( mipmaps && mipmaps.length > 0 ) {

                    state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] );

                } else {

                    state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );

                }

                for ( let i = 0; i < textures.length; i ++ ) {

                    if ( renderTarget.resolveDepthBuffer ) {

                        if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;

                        // resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)

                        if ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;

                    }

                    if ( isMultipleRenderTargets ) {

                        _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                        const webglTexture = properties.get( textures[ i ] ).__webglTexture;
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );

                    }

                    _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );

                    if ( supportsInvalidateFramebuffer === true ) {

                        invalidationArrayRead.length = 0;
                        invalidationArrayDraw.length = 0;

                        invalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i );

                        if ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false ) {

                            invalidationArrayRead.push( depthStyle );
                            invalidationArrayDraw.push( depthStyle );

                            _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, invalidationArrayDraw );

                        }

                        _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArrayRead );

                    }

                }

                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( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                        const webglTexture = properties.get( textures[ i ] ).__webglTexture;

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );

                    }

                }

                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );

            } else {

                if ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer ) {

                    const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;

                    _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );

                }

            }

        }

    }

    function getRenderTargetSamples( renderTarget ) {

        return Math.min( capabilities.maxSamples, renderTarget.samples );

    }

    function useMultisampledRTT( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );

        return renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;

    }

    function updateVideoTexture( texture ) {

        const frame = info.render.frame;

        // Check the last frame we updated the VideoTexture

        if ( _videoTextures.get( texture ) !== frame ) {

            _videoTextures.set( texture, frame );
            texture.update();

        }

    }

    function verifyColorSpace( texture, image ) {

        const colorSpace = texture.colorSpace;
        const format = texture.format;
        const type = texture.type;

        if ( texture.isCompressedTexture === true || texture.isVideoTexture === true ) return image;

        if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {

            // sRGB

            if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {

                // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format

                if ( format !== RGBAFormat || type !== UnsignedByteType ) {

                    console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );

                }

            } else {

                console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );

            }

        }

        return image;

    }

    function getDimensions( image ) {

        if ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) {

            // if intrinsic data are not available, fallback to width/height

            _imageDimensions.width = image.naturalWidth || image.width;
            _imageDimensions.height = image.naturalHeight || image.height;

        } else if ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) {

            _imageDimensions.width = image.displayWidth;
            _imageDimensions.height = image.displayHeight;

        } else {

            _imageDimensions.width = image.width;
            _imageDimensions.height = image.height;

        }

        return _imageDimensions;

    }

    //

    this.allocateTextureUnit = allocateTextureUnit;
    this.resetTextureUnits = resetTextureUnits;

    this.setTexture2D = setTexture2D;
    this.setTexture2DArray = setTexture2DArray;
    this.setTexture3D = setTexture3D;
    this.setTextureCube = setTextureCube;
    this.rebindTextures = rebindTextures;
    this.setupRenderTarget = setupRenderTarget;
    this.updateRenderTargetMipmap = updateRenderTargetMipmap;
    this.updateMultisampleRenderTarget = updateMultisampleRenderTarget;
    this.setupDepthRenderbuffer = setupDepthRenderbuffer;
    this.setupFrameBufferTexture = setupFrameBufferTexture;
    this.useMultisampledRTT = useMultisampledRTT;

}

createCanvas(width: any, height: any): HTMLElement | OffscreenCanvas

Parameters:

  • width any
  • height any

Returns: HTMLElement | OffscreenCanvas

Calls:

  • createElementNS (from ./three.core.js)

Internal Comments:

// Use OffscreenCanvas when available. Specially needed in web workers
// eslint-disable-next-line compat/compat

Code
function createCanvas( width, height ) {

        // Use OffscreenCanvas when available. Specially needed in web workers

        return useOffscreenCanvas ?
            // eslint-disable-next-line compat/compat
            new OffscreenCanvas( width, height ) : createElementNS( 'canvas' );

    }

resizeImage(image: any, needsNewCanvas: any, maxSize: any): any

Parameters:

  • image any
  • needsNewCanvas any
  • maxSize any

Returns: any

Calls:

  • getDimensions
  • Math.max
  • Math.floor
  • createCanvas
  • canvas.getContext
  • context.drawImage
  • console.warn

Internal Comments:

// handle case if texture exceeds max size
// only perform resize if necessary
// only perform resize for certain image types
// cube textures can't reuse the same canvas (x2)

Code
function resizeImage( image, needsNewCanvas, maxSize ) {

        let scale = 1;

        const dimensions = getDimensions( image );

        // handle case if texture exceeds max size

        if ( dimensions.width > maxSize || dimensions.height > maxSize ) {

            scale = maxSize / Math.max( dimensions.width, dimensions.height );

        }

        // only perform resize if necessary

        if ( scale < 1 ) {

            // only perform resize for certain image types

            if ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||
                ( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||
                ( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ||
                ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) ) {

                const width = Math.floor( scale * dimensions.width );
                const height = Math.floor( scale * dimensions.height );

                if ( _canvas === undefined ) _canvas = createCanvas( width, height );

                // cube textures can't reuse the same canvas

                const canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;

                canvas.width = width;
                canvas.height = height;

                const context = canvas.getContext( '2d' );
                context.drawImage( image, 0, 0, width, height );

                console.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').' );

                return canvas;

            } else {

                if ( 'data' in image ) {

                    console.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').' );

                }

                return image;

            }

        }

        return image;

    }

textureNeedsGenerateMipmaps(texture: any): any

Parameters:

  • texture any

Returns: any

Code
function textureNeedsGenerateMipmaps( texture ) {

        return texture.generateMipmaps;

    }

generateMipmap(target: any): void

Parameters:

  • target any

Returns: void

Calls:

  • _gl.generateMipmap
Code
function generateMipmap( target ) {

        _gl.generateMipmap( target );

    }

getTargetType(texture: any): any

Parameters:

  • texture any

Returns: any

Code
function getTargetType( texture ) {

        if ( texture.isWebGLCubeRenderTarget ) return _gl.TEXTURE_CUBE_MAP;
        if ( texture.isWebGL3DRenderTarget ) return _gl.TEXTURE_3D;
        if ( texture.isWebGLArrayRenderTarget || texture.isCompressedArrayTexture ) return _gl.TEXTURE_2D_ARRAY;
        return _gl.TEXTURE_2D;

    }

getInternalFormat(internalFormatName: any, glFormat: any, glType: any, colorSpace: any, forceLinearTransfer: boolean): any

Parameters:

  • internalFormatName any
  • glFormat any
  • glType any
  • colorSpace any
  • forceLinearTransfer boolean

Returns: any

Calls:

  • console.warn
  • ColorManagement.getTransfer
  • extensions.get
Code
function getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {

        if ( internalFormatName !== null ) {

            if ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];

            console.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \'' + internalFormatName + '\'' );

        }

        let internalFormat = glFormat;

        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 === _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 === _gl.RG ) {

            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 === _gl.RG_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RG16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RG32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RG8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RG16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RG32I;

        }

        if ( glFormat === _gl.RGB_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGB8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGB16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGB32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RGB8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RGB16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RGB32I;

        }

        if ( glFormat === _gl.RGBA_INTEGER ) {

            if ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RGBA8UI;
            if ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RGBA16UI;
            if ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RGBA32UI;
            if ( glType === _gl.BYTE ) internalFormat = _gl.RGBA8I;
            if ( glType === _gl.SHORT ) internalFormat = _gl.RGBA16I;
            if ( glType === _gl.INT ) internalFormat = _gl.RGBA32I;

        }

        if ( glFormat === _gl.RGB ) {

            if ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;

        }

        if ( glFormat === _gl.RGBA ) {

            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 === _gl.R16F || internalFormat === _gl.R32F ||
            internalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||
            internalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {

            extensions.get( 'EXT_color_buffer_float' );

        }

        return internalFormat;

    }

getInternalDepthFormat(useStencil: any, depthType: any): any

Parameters:

  • useStencil any
  • depthType any

Returns: any

Calls:

  • console.warn
Code
function getInternalDepthFormat( useStencil, depthType ) {

        let glInternalFormat;
        if ( useStencil ) {

            if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {

                glInternalFormat = _gl.DEPTH24_STENCIL8;

            } else if ( depthType === FloatType ) {

                glInternalFormat = _gl.DEPTH32F_STENCIL8;

            } else if ( depthType === UnsignedShortType ) {

                glInternalFormat = _gl.DEPTH24_STENCIL8;
                console.warn( 'DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.' );

            }

        } else {

            if ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {

                glInternalFormat = _gl.DEPTH_COMPONENT24;

            } else if ( depthType === FloatType ) {

                glInternalFormat = _gl.DEPTH_COMPONENT32F;

            } else if ( depthType === UnsignedShortType ) {

                glInternalFormat = _gl.DEPTH_COMPONENT16;

            }

        }

        return glInternalFormat;

    }

getMipLevels(texture: any, image: any): any

Parameters:

  • texture any
  • image any

Returns: any

Calls:

  • textureNeedsGenerateMipmaps
  • Math.log2
  • Math.max
  • Array.isArray

Internal Comments:

// user-defined mipmaps
// texture without mipmaps (only base level)

Code
function getMipLevels( texture, image ) {

        if ( textureNeedsGenerateMipmaps( texture ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {

            return Math.log2( Math.max( image.width, image.height ) ) + 1;

        } else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {

            // user-defined mipmaps

            return texture.mipmaps.length;

        } else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {

            return image.mipmaps.length;

        } else {

            // texture without mipmaps (only base level)

            return 1;

        }

    }

onTextureDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • texture.removeEventListener
  • deallocateTexture
  • _videoTextures.delete
Code
function onTextureDispose( event ) {

        const texture = event.target;

        texture.removeEventListener( 'dispose', onTextureDispose );

        deallocateTexture( texture );

        if ( texture.isVideoTexture ) {

            _videoTextures.delete( texture );

        }

    }

onRenderTargetDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • renderTarget.removeEventListener
  • deallocateRenderTarget
Code
function onRenderTargetDispose( event ) {

        const renderTarget = event.target;

        renderTarget.removeEventListener( 'dispose', onRenderTargetDispose );

        deallocateRenderTarget( renderTarget );

    }

deallocateTexture(texture: any): void

Parameters:

  • texture any

Returns: void

Calls:

  • properties.get
  • _sources.get
  • deleteTexture
  • Object.keys
  • _sources.delete
  • properties.remove

Internal Comments:

// check if it's necessary to remove the WebGLTexture object (x2)
// the WebGLTexture object is not used anymore, remove it
// remove the weak map entry if no WebGLTexture uses the source anymore

Code
function deallocateTexture( texture ) {

        const textureProperties = properties.get( texture );

        if ( textureProperties.__webglInit === undefined ) return;

        // check if it's necessary to remove the WebGLTexture object

        const source = texture.source;
        const webglTextures = _sources.get( source );

        if ( webglTextures ) {

            const webglTexture = webglTextures[ textureProperties.__cacheKey ];
            webglTexture.usedTimes --;

            // the WebGLTexture object is not used anymore, remove it

            if ( webglTexture.usedTimes === 0 ) {

                deleteTexture( texture );

            }

            // remove the weak map entry if no WebGLTexture uses the source anymore

            if ( Object.keys( webglTextures ).length === 0 ) {

                _sources.delete( source );

            }

        }

        properties.remove( texture );

    }

deleteTexture(texture: any): void

Parameters:

  • texture any

Returns: void

Calls:

  • properties.get
  • _gl.deleteTexture
  • _sources.get
Code
function deleteTexture( texture ) {

        const textureProperties = properties.get( texture );
        _gl.deleteTexture( textureProperties.__webglTexture );

        const source = texture.source;
        const webglTextures = _sources.get( source );
        delete webglTextures[ textureProperties.__cacheKey ];

        info.memory.textures --;

    }

deallocateRenderTarget(renderTarget: any): void

Parameters:

  • renderTarget any

Returns: void

Calls:

  • properties.get
  • renderTarget.depthTexture.dispose
  • properties.remove
  • Array.isArray
  • _gl.deleteFramebuffer
  • _gl.deleteRenderbuffer
  • _gl.deleteTexture
Code
function deallocateRenderTarget( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );

        if ( renderTarget.depthTexture ) {

            renderTarget.depthTexture.dispose();

            properties.remove( renderTarget.depthTexture );

        }

        if ( renderTarget.isWebGLCubeRenderTarget ) {

            for ( let i = 0; i < 6; 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 {

            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 );

            if ( renderTargetProperties.__webglColorRenderbuffer ) {

                for ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {

                    if ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );

                }

            }

            if ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );

        }

        const textures = renderTarget.textures;

        for ( let i = 0, il = textures.length; i < il; i ++ ) {

            const attachmentProperties = properties.get( textures[ i ] );

            if ( attachmentProperties.__webglTexture ) {

                _gl.deleteTexture( attachmentProperties.__webglTexture );

                info.memory.textures --;

            }

            properties.remove( textures[ i ] );

        }

        properties.remove( renderTarget );

    }

resetTextureUnits(): void

Returns: void

Code
function resetTextureUnits() {

        textureUnits = 0;

    }

allocateTextureUnit(): number

Returns: number

Calls:

  • console.warn
Code
function allocateTextureUnit() {

        const textureUnit = textureUnits;

        if ( textureUnit >= capabilities.maxTextures ) {

            console.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );

        }

        textureUnits += 1;

        return textureUnit;

    }

getTextureCacheKey(texture: any): string

Parameters:

  • texture any

Returns: string

Calls:

  • array.push
  • array.join
Code
function getTextureCacheKey( texture ) {

        const array = [];

        array.push( texture.wrapS );
        array.push( texture.wrapT );
        array.push( texture.wrapR || 0 );
        array.push( texture.magFilter );
        array.push( texture.minFilter );
        array.push( texture.anisotropy );
        array.push( texture.internalFormat );
        array.push( texture.format );
        array.push( texture.type );
        array.push( texture.generateMipmaps );
        array.push( texture.premultiplyAlpha );
        array.push( texture.flipY );
        array.push( texture.unpackAlignment );
        array.push( texture.colorSpace );

        return array.join();

    }

setTexture2D(texture: any, slot: any): void

Parameters:

  • texture any
  • slot any

Returns: void

Calls:

  • properties.get
  • updateVideoTexture
  • console.warn
  • uploadTexture
  • state.bindTexture
Code
function setTexture2D( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isVideoTexture ) updateVideoTexture( texture );

        if ( texture.isRenderTargetTexture === false && texture.isExternalTexture !== true && texture.version > 0 && textureProperties.__version !== texture.version ) {

            const image = texture.image;

            if ( image === null ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );

            } else if ( image.complete === false ) {

                console.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );

            } else {

                uploadTexture( textureProperties, texture, slot );
                return;

            }

        } else if ( texture.isExternalTexture ) {

            textureProperties.__webglTexture = texture.sourceTexture ? texture.sourceTexture : null;

        }

        state.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

setTexture2DArray(texture: any, slot: any): void

Parameters:

  • texture any
  • slot any

Returns: void

Calls:

  • properties.get
  • uploadTexture
  • state.bindTexture
Code
function setTexture2DArray( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

setTexture3D(texture: any, slot: any): void

Parameters:

  • texture any
  • slot any

Returns: void

Calls:

  • properties.get
  • uploadTexture
  • state.bindTexture
Code
function setTexture3D( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

setTextureCube(texture: any, slot: any): void

Parameters:

  • texture any
  • slot any

Returns: void

Calls:

  • properties.get
  • uploadCubeTexture
  • state.bindTexture
Code
function setTextureCube( texture, slot ) {

        const textureProperties = properties.get( texture );

        if ( texture.version > 0 && textureProperties.__version !== texture.version ) {

            uploadCubeTexture( textureProperties, texture, slot );
            return;

        }

        state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );

    }

setTextureParameters(textureType: any, texture: any): void

Parameters:

  • textureType any
  • texture any

Returns: void

Calls:

  • extensions.has
  • console.warn
  • _gl.texParameteri
  • properties.get
  • extensions.get
  • _gl.texParameterf
  • Math.min
  • capabilities.getMaxAnisotropy
Code
function setTextureParameters( textureType, texture ) {

        if ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false &&
            ( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter ||
            texture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) {

            console.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' );

        }

        _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );
        _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );

        if ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {

            _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );

        }

        _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );
        _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );

        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 ) {

            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

            if ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {

                const extension = extensions.get( 'EXT_texture_filter_anisotropic' );
                _gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );
                properties.get( texture ).__currentAnisotropy = texture.anisotropy;

            }

        }

    }

initTexture(textureProperties: any, texture: any): boolean

Parameters:

  • textureProperties any
  • texture any

Returns: boolean

Calls:

  • texture.addEventListener
  • _sources.get
  • _sources.set
  • getTextureCacheKey
  • _gl.createTexture
  • deleteTexture

Internal Comments:

// create Source <-> WebGLTextures mapping if necessary (x2)
// check if there is already a WebGLTexture object for the given texture parameters (x2)
// if not, create a new instance of WebGLTexture
// create new entry (x4)
// when a new instance of WebGLTexture was created, a texture upload is required (x3)
// even if the image contents are identical (x3)
// every time the texture cache key changes, it's necessary to check if an instance of (x2)
// WebGLTexture can be deleted in order to avoid a memory leak. (x2)
// store references to cache key and WebGLTexture object (x4)

Code
function initTexture( textureProperties, texture ) {

        let forceUpload = false;

        if ( textureProperties.__webglInit === undefined ) {

            textureProperties.__webglInit = true;

            texture.addEventListener( 'dispose', onTextureDispose );

        }

        // create Source <-> WebGLTextures mapping if necessary

        const source = texture.source;
        let webglTextures = _sources.get( source );

        if ( webglTextures === undefined ) {

            webglTextures = {};
            _sources.set( source, webglTextures );

        }

        // check if there is already a WebGLTexture object for the given texture parameters

        const textureCacheKey = getTextureCacheKey( texture );

        if ( textureCacheKey !== textureProperties.__cacheKey ) {

            // if not, create a new instance of WebGLTexture

            if ( webglTextures[ textureCacheKey ] === undefined ) {

                // create new entry

                webglTextures[ textureCacheKey ] = {
                    texture: _gl.createTexture(),
                    usedTimes: 0
                };

                info.memory.textures ++;

                // when a new instance of WebGLTexture was created, a texture upload is required
                // even if the image contents are identical

                forceUpload = true;

            }

            webglTextures[ textureCacheKey ].usedTimes ++;

            // every time the texture cache key changes, it's necessary to check if an instance of
            // WebGLTexture can be deleted in order to avoid a memory leak.

            const webglTexture = webglTextures[ textureProperties.__cacheKey ];

            if ( webglTexture !== undefined ) {

                webglTextures[ textureProperties.__cacheKey ].usedTimes --;

                if ( webglTexture.usedTimes === 0 ) {

                    deleteTexture( texture );

                }

            }

            // store references to cache key and WebGLTexture object

            textureProperties.__cacheKey = textureCacheKey;
            textureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;

        }

        return forceUpload;

    }

getRow(index: any, rowLength: any, componentStride: any): number

Parameters:

  • index any
  • rowLength any
  • componentStride any

Returns: number

Calls:

  • Math.floor
Code
function getRow( index, rowLength, componentStride ) {

        return Math.floor( Math.floor( index / componentStride ) / rowLength );

    }

updateTexture(texture: any, image: any, glFormat: any, glType: any): void

Parameters:

  • texture any
  • image any
  • glFormat any
  • glType any

Returns: void

Calls:

  • state.texSubImage2D
  • updateRanges.sort
  • getRow
  • Math.max
  • _gl.getParameter
  • _gl.pixelStorei
  • Math.floor
  • Math.ceil
  • texture.clearUpdateRanges

Internal Comments:

// Before applying update ranges, we merge any adjacent / overlapping (x4)
// ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led (x4)
// to performance improvements for applications which make heavy use of (x4)
// update ranges. Likely due to GPU command overhead. (x4)
// (x4)
// Note that to reduce garbage collection between frames, we merge the (x4)
// update ranges in-place. This is safe because this method will clear the (x4)
// update ranges once updated. (x4)
// To merge the update ranges in-place, we work from left to right in the (x2)
// existing updateRanges array, merging ranges. This may result in a final (x2)
// array which is smaller than the original. This index tracks the last (x2)
// index representing a merged range, any data after this index can be (x2)
// trimmed once the merge algorithm is completed. (x2)
// Only merge if in the same row and overlapping/adjacent (x2)
// We add one here to merge adjacent ranges. This is safe because ranges
// operate over positive integers.
// Trim the array to only contain the merged ranges. (x4)
// Assumes update ranges refer to contiguous memory (x2)

Code
function updateTexture( texture, image, glFormat, glType ) {

        const componentStride = 4; // only RGBA supported

        const updateRanges = texture.updateRanges;

        if ( updateRanges.length === 0 ) {

            state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );

        } else {

            // Before applying update ranges, we merge any adjacent / overlapping
            // ranges to reduce load on `gl.texSubImage2D`. Empirically, this has led
            // to performance improvements for applications which make heavy use of
            // update ranges. Likely due to GPU command overhead.
            //
            // Note that to reduce garbage collection between frames, we merge the
            // update ranges in-place. This is safe because this method will clear the
            // update ranges once updated.

            updateRanges.sort( ( a, b ) => a.start - b.start );

            // To merge the update ranges in-place, we work from left to right in the
            // existing updateRanges array, merging ranges. This may result in a final
            // array which is smaller than the original. This index tracks the last
            // index representing a merged range, any data after this index can be
            // trimmed once the merge algorithm is completed.
            let mergeIndex = 0;

            for ( let i = 1; i < updateRanges.length; i ++ ) {

                const previousRange = updateRanges[ mergeIndex ];
                const range = updateRanges[ i ];

                // Only merge if in the same row and overlapping/adjacent
                const previousEnd = previousRange.start + previousRange.count;
                const currentRow = getRow( range.start, image.width, componentStride );
                const previousRow = getRow( previousRange.start, image.width, componentStride );

                // We add one here to merge adjacent ranges. This is safe because ranges
                // operate over positive integers.
                if (
                    range.start <= previousEnd + 1 &&
                    currentRow === previousRow &&
                    getRow( range.start + range.count - 1, image.width, componentStride ) === currentRow // ensure range doesn't spill
                ) {

                    previousRange.count = Math.max(
                        previousRange.count,
                        range.start + range.count - previousRange.start
                    );

                } else {

                    ++ mergeIndex;
                    updateRanges[ mergeIndex ] = range;

                }


            }

            // Trim the array to only contain the merged ranges.
            updateRanges.length = mergeIndex + 1;

            const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
            const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
            const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );

            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );

            for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {

                const range = updateRanges[ i ];

                const pixelStart = Math.floor( range.start / componentStride );
                const pixelCount = Math.ceil( range.count / componentStride );

                const x = pixelStart % image.width;
                const y = Math.floor( pixelStart / image.width );

                // Assumes update ranges refer to contiguous memory
                const width = pixelCount;
                const height = 1;

                _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, x );
                _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, y );

                state.texSubImage2D( _gl.TEXTURE_2D, 0, x, y, width, height, glFormat, glType, image.data );

            }

            texture.clearUpdateRanges();

            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
            _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
            _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );

        }

    }

uploadTexture(textureProperties: any, texture: any, slot: any): void

Parameters:

  • textureProperties any
  • texture any
  • slot any

Returns: void

Calls:

  • initTexture
  • state.bindTexture
  • properties.get
  • state.activeTexture
  • ColorManagement.getPrimaries
  • _gl.pixelStorei
  • resizeImage
  • verifyColorSpace
  • utils.convert
  • getInternalFormat
  • setTextureParameters
  • getMipLevels
  • getInternalDepthFormat
  • state.texStorage2D
  • state.texImage2D
  • state.texSubImage2D
  • updateTexture
  • state.texStorage3D
  • getByteLength (from ./three.core.js)
  • mipmap.data.subarray
  • state.compressedTexSubImage3D
  • texture.clearLayerUpdates
  • state.compressedTexImage3D
  • console.warn
  • state.texSubImage3D
  • state.texImage3D
  • state.compressedTexSubImage2D
  • state.compressedTexImage2D
  • image.data.subarray
  • getDimensions
  • textureNeedsGenerateMipmaps
  • generateMipmap
  • texture.onUpdate

Internal Comments:

//
// use manually created mipmaps if available (x2)
// if there are no manual mipmaps (x2)
// set 0 level mipmap and then use GL to generate other mipmap levels (x2)
// regular Texture (image, video, canvas)

Code
function uploadTexture( textureProperties, texture, slot ) {

        let textureType = _gl.TEXTURE_2D;

        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, _gl.TEXTURE0 + slot );

        const sourceProperties = properties.get( source );

        if ( source.version !== sourceProperties.__version || forceUpload === true ) {

            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( _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 );

            let image = resizeImage( texture.image, false, capabilities.maxTextureSize );
            image = verifyColorSpace( texture, image );

            const glFormat = utils.convert( texture.format, texture.colorSpace );

            const glType = utils.convert( texture.type );
            let glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );

            setTextureParameters( textureType, texture );

            let mipmap;
            const mipmaps = texture.mipmaps;

            const useTexStorage = ( texture.isVideoTexture !== true );
            const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
            const dataReady = source.dataReady;
            const levels = getMipLevels( texture, image );

            if ( texture.isDepthTexture ) {

                glInternalFormat = getInternalDepthFormat( texture.format === DepthStencilFormat, texture.type );

                //

                if ( allocateMemory ) {

                    if ( useTexStorage ) {

                        state.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );

                    }

                }

            } else if ( texture.isDataTexture ) {

                // use manually created mipmaps if available
                // if there are no manual mipmaps
                // set 0 level mipmap and then use GL to generate other mipmap levels

                if ( mipmaps.length > 0 ) {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                        }

                    }

                    texture.generateMipmaps = false;

                } else {

                    if ( useTexStorage ) {

                        if ( allocateMemory ) {

                            state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );

                        }

                        if ( dataReady ) {

                            updateTexture( texture, image, glFormat, glType );

                        }

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );

                    }

                }

            } else if ( texture.isCompressedTexture ) {

                if ( texture.isCompressedArrayTexture ) {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        if ( texture.layerUpdates.size > 0 ) {

                                            const layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );

                                            for ( const layerIndex of texture.layerUpdates ) {

                                                const layerData = mipmap.data.subarray(
                                                    layerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT,
                                                    ( layerIndex + 1 ) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT
                                                );
                                                state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData );

                                            }

                                            texture.clearLayerUpdates();

                                        } else {

                                            state.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data );

                                        }

                                    }

                                } else {

                                    state.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                } else {

                    if ( useTexStorage && allocateMemory ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        state.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );

                                    }

                                } else {

                                    state.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                }

            } else if ( texture.isDataArrayTexture ) {

                if ( useTexStorage ) {

                    if ( allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );

                    }

                    if ( dataReady ) {

                        if ( texture.layerUpdates.size > 0 ) {

                            const layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type );

                            for ( const layerIndex of texture.layerUpdates ) {

                                const layerData = image.data.subarray(
                                    layerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT,
                                    ( layerIndex + 1 ) * layerByteLength / image.data.BYTES_PER_ELEMENT
                                );
                                state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData );

                            }

                            texture.clearLayerUpdates();

                        } else {

                            state.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );

                        }

                    }

                } else {

                    state.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );

                }

            } else if ( texture.isData3DTexture ) {

                if ( useTexStorage ) {

                    if ( allocateMemory ) {

                        state.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );

                    }

                    if ( dataReady ) {

                        state.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );

                    }

                } else {

                    state.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );

                }

            } else if ( texture.isFramebufferTexture ) {

                if ( allocateMemory ) {

                    if ( useTexStorage ) {

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );

                    } else {

                        let width = image.width, height = image.height;

                        for ( let i = 0; i < levels; i ++ ) {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );

                            width >>= 1;
                            height >>= 1;

                        }

                    }

                }

            } else {

                // regular Texture (image, video, canvas)

                // use manually created mipmaps if available
                // if there are no manual mipmaps
                // set 0 level mipmap and then use GL to generate other mipmap levels

                if ( mipmaps.length > 0 ) {

                    if ( useTexStorage && allocateMemory ) {

                        const dimensions = getDimensions( mipmaps[ 0 ] );

                        state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );

                    }

                    for ( let i = 0, il = mipmaps.length; i < il; i ++ ) {

                        mipmap = mipmaps[ i ];

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );

                        }

                    }

                    texture.generateMipmaps = false;

                } else {

                    if ( useTexStorage ) {

                        if ( allocateMemory ) {

                            const dimensions = getDimensions( image );

                            state.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );

                        }

                        if ( dataReady ) {

                            state.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );

                        }

                    } else {

                        state.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );

                    }

                }

            }

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                generateMipmap( textureType );

            }

            sourceProperties.__version = source.version;

            if ( texture.onUpdate ) texture.onUpdate( texture );

        }

        textureProperties.__version = texture.version;

    }

uploadCubeTexture(textureProperties: any, texture: any, slot: any): void

Parameters:

  • textureProperties any
  • texture any
  • slot any

Returns: void

Calls:

  • initTexture
  • state.bindTexture
  • properties.get
  • state.activeTexture
  • ColorManagement.getPrimaries
  • _gl.pixelStorei
  • resizeImage
  • verifyColorSpace
  • utils.convert
  • getInternalFormat
  • getMipLevels
  • setTextureParameters
  • state.texStorage2D
  • state.compressedTexSubImage2D
  • state.compressedTexImage2D
  • console.warn
  • state.texSubImage2D
  • state.texImage2D
  • getDimensions
  • textureNeedsGenerateMipmaps
  • generateMipmap
  • texture.onUpdate

Internal Comments:

// TODO: Uniformly handle mipmap definitions
// Normal textures and compressed cube textures define base level + mips with their mipmap array
// Uncompressed cube textures use their mipmap array only for mips (no base level)
// We assume images for cube map have the same size. (x3)

Code
function uploadCubeTexture( textureProperties, texture, slot ) {

        if ( texture.image.length !== 6 ) return;

        const forceUpload = initTexture( textureProperties, texture );
        const source = texture.source;

        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( _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( _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 );

            const cubeImage = [];

            for ( let i = 0; i < 6; i ++ ) {

                if ( ! isCompressed && ! isDataTexture ) {

                    cubeImage[ i ] = resizeImage( texture.image[ i ], true, capabilities.maxCubemapSize );

                } else {

                    cubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];

                }

                cubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );

            }

            const image = cubeImage[ 0 ],
                glFormat = utils.convert( texture.format, texture.colorSpace ),
                glType = utils.convert( texture.type ),
                glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );

            const useTexStorage = ( texture.isVideoTexture !== true );
            const allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );
            const dataReady = source.dataReady;
            let levels = getMipLevels( texture, image );

            setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );

            let mipmaps;

            if ( isCompressed ) {

                if ( useTexStorage && allocateMemory ) {

                    state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );

                }

                for ( let i = 0; i < 6; i ++ ) {

                    mipmaps = cubeImage[ i ].mipmaps;

                    for ( let j = 0; j < mipmaps.length; j ++ ) {

                        const mipmap = mipmaps[ j ];

                        if ( texture.format !== RGBAFormat ) {

                            if ( glFormat !== null ) {

                                if ( useTexStorage ) {

                                    if ( dataReady ) {

                                        state.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );

                                    }

                                } else {

                                    state.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );

                                }

                            } else {

                                console.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );

                            }

                        } else {

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );

                            }

                        }

                    }

                }

            } else {

                mipmaps = texture.mipmaps;

                if ( useTexStorage && allocateMemory ) {

                    // TODO: Uniformly handle mipmap definitions
                    // Normal textures and compressed cube textures define base level + mips with their mipmap array
                    // Uncompressed cube textures use their mipmap array only for mips (no base level)

                    if ( mipmaps.length > 0 ) levels ++;

                    const dimensions = getDimensions( cubeImage[ 0 ] );

                    state.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height );

                }

                for ( let i = 0; i < 6; i ++ ) {

                    if ( isDataTexture ) {

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                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( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );

                        }

                        for ( let j = 0; j < mipmaps.length; j ++ ) {

                            const mipmap = mipmaps[ j ];
                            const mipmapImage = mipmap.image[ i ].image;

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );

                            }

                        }

                    } else {

                        if ( useTexStorage ) {

                            if ( dataReady ) {

                                state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );

                            }

                        } else {

                            state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );

                        }

                        for ( let j = 0; j < mipmaps.length; j ++ ) {

                            const mipmap = mipmaps[ j ];

                            if ( useTexStorage ) {

                                if ( dataReady ) {

                                    state.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );

                                }

                            } else {

                                state.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );

                            }

                        }

                    }

                }

            }

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                // We assume images for cube map have the same size.
                generateMipmap( _gl.TEXTURE_CUBE_MAP );

            }

            sourceProperties.__version = source.version;

            if ( texture.onUpdate ) texture.onUpdate( texture );

        }

        textureProperties.__version = texture.version;

    }

setupFrameBufferTexture(framebuffer: any, renderTarget: any, texture: any, attachment: any, textureTarget: any, level: any): void

Parameters:

  • framebuffer any
  • renderTarget any
  • texture any
  • attachment any
  • textureTarget any
  • level any

Returns: void

Calls:

  • utils.convert
  • getInternalFormat
  • properties.get
  • Math.max
  • state.texImage3D
  • state.texImage2D
  • state.bindFramebuffer
  • useMultisampledRTT
  • multisampledRTTExt.framebufferTexture2DMultisampleEXT
  • getRenderTargetSamples
  • _gl.framebufferTexture2D
Code
function setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {

        const glFormat = utils.convert( texture.format, texture.colorSpace );
        const glType = utils.convert( texture.type );
        const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
        const renderTargetProperties = properties.get( renderTarget );
        const textureProperties = properties.get( texture );

        textureProperties.__renderTarget = renderTarget;

        if ( ! renderTargetProperties.__hasExternalTextures ) {

            const width = Math.max( 1, renderTarget.width >> level );
            const height = Math.max( 1, renderTarget.height >> level );

            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, level, glInternalFormat, width, height, 0, glFormat, glType, null );

            }

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

        if ( useMultisampledRTT( renderTarget ) ) {

            multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, 0, getRenderTargetSamples( renderTarget ) );

        } else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753

            _gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, textureProperties.__webglTexture, level );

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

setupRenderBufferStorage(renderbuffer: any, renderTarget: any, isMultisample: any): void

Parameters:

  • renderbuffer any
  • renderTarget any
  • isMultisample any

Returns: void

Calls:

  • _gl.bindRenderbuffer
  • getInternalDepthFormat
  • getRenderTargetSamples
  • useMultisampledRTT
  • multisampledRTTExt.renderbufferStorageMultisampleEXT
  • _gl.renderbufferStorageMultisample
  • _gl.renderbufferStorage
  • _gl.framebufferRenderbuffer
  • utils.convert
  • getInternalFormat

Internal Comments:

// retrieve the depth attachment types (x2)
// set up the attachment (x2)

Code
function setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );

        if ( renderTarget.depthBuffer ) {

            // retrieve the depth attachment types
            const depthTexture = renderTarget.depthTexture;
            const depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null;
            const glInternalFormat = getInternalDepthFormat( renderTarget.stencilBuffer, depthType );
            const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;

            // set up the attachment
            const samples = getRenderTargetSamples( renderTarget );
            const isUseMultisampledRTT = useMultisampledRTT( renderTarget );
            if ( isUseMultisampledRTT ) {

                multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

            } else if ( isMultisample ) {

                _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

            } else {

                _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );

            }

            _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

        } else {

            const textures = renderTarget.textures;

            for ( let i = 0; i < textures.length; i ++ ) {

                const texture = textures[ i ];

                const glFormat = utils.convert( texture.format, texture.colorSpace );
                const glType = utils.convert( texture.type );
                const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );
                const samples = getRenderTargetSamples( renderTarget );

                if ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {

                    _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                } else if ( useMultisampledRTT( renderTarget ) ) {

                    multisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                } else {

                    _gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );

                }

            }

        }

        _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

    }

setupDepthTexture(framebuffer: any, renderTarget: any): void

Parameters:

  • framebuffer any
  • renderTarget any

Returns: void

Calls:

  • state.bindFramebuffer
  • properties.get
  • setTexture2D
  • getRenderTargetSamples
  • useMultisampledRTT
  • multisampledRTTExt.framebufferTexture2DMultisampleEXT
  • _gl.framebufferTexture2D

Internal Comments:

// upload an empty depth texture with framebuffer size

Code
function setupDepthTexture( framebuffer, renderTarget ) {

        const isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );
        if ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );

        state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

        if ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {

            throw new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );

        }

        const textureProperties = properties.get( renderTarget.depthTexture );
        textureProperties.__renderTarget = renderTarget;

        // upload an empty depth texture with framebuffer size
        if ( ! textureProperties.__webglTexture ||
                renderTarget.depthTexture.image.width !== renderTarget.width ||
                renderTarget.depthTexture.image.height !== renderTarget.height ) {

            renderTarget.depthTexture.image.width = renderTarget.width;
            renderTarget.depthTexture.image.height = renderTarget.height;
            renderTarget.depthTexture.needsUpdate = true;

        }

        setTexture2D( renderTarget.depthTexture, 0 );

        const webglDepthTexture = textureProperties.__webglTexture;
        const samples = getRenderTargetSamples( renderTarget );

        if ( renderTarget.depthTexture.format === DepthFormat ) {

            if ( useMultisampledRTT( renderTarget ) ) {

                multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );

            } else {

                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

            }

        } else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {

            if ( useMultisampledRTT( renderTarget ) ) {

                multisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );

            } else {

                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );

            }

        } else {

            throw new Error( 'Unknown depthTexture format' );

        }

    }

setupDepthRenderbuffer(renderTarget: any): void

Parameters:

  • renderTarget any

Returns: void

Calls:

  • properties.get
  • renderTargetProperties.__depthDisposeCallback
  • depthTexture.removeEventListener
  • depthTexture.addEventListener
  • setupDepthTexture
  • state.bindFramebuffer
  • _gl.createRenderbuffer
  • setupRenderBufferStorage
  • _gl.bindRenderbuffer
  • _gl.framebufferRenderbuffer

Internal Comments:

// if the bound depth texture has changed
// fire the dispose event to get rid of stored state associated with the previously bound depth buffer (x2)
// set up dispose listeners to track when the currently attached buffer is implicitly unbound
// attach buffer if it's been created already (x4)

Code
function setupDepthRenderbuffer( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );
        const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );

        // if the bound depth texture has changed
        if ( renderTargetProperties.__boundDepthTexture !== renderTarget.depthTexture ) {

            // fire the dispose event to get rid of stored state associated with the previously bound depth buffer
            const depthTexture = renderTarget.depthTexture;
            if ( renderTargetProperties.__depthDisposeCallback ) {

                renderTargetProperties.__depthDisposeCallback();

            }

            // set up dispose listeners to track when the currently attached buffer is implicitly unbound
            if ( depthTexture ) {

                const disposeEvent = () => {

                    delete renderTargetProperties.__boundDepthTexture;
                    delete renderTargetProperties.__depthDisposeCallback;
                    depthTexture.removeEventListener( 'dispose', disposeEvent );

                };

                depthTexture.addEventListener( 'dispose', disposeEvent );
                renderTargetProperties.__depthDisposeCallback = disposeEvent;

            }

            renderTargetProperties.__boundDepthTexture = depthTexture;

        }

        if ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {

            if ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );

            const mipmaps = renderTarget.texture.mipmaps;

            if ( mipmaps && mipmaps.length > 0 ) {

                setupDepthTexture( renderTargetProperties.__webglFramebuffer[ 0 ], renderTarget );

            } else {

                setupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );

            }

        } else {

            if ( isCube ) {

                renderTargetProperties.__webglDepthbuffer = [];

                for ( let i = 0; i < 6; i ++ ) {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );

                    if ( renderTargetProperties.__webglDepthbuffer[ i ] === undefined ) {

                        renderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();
                        setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );

                    } else {

                        // attach buffer if it's been created already
                        const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                        const renderbuffer = renderTargetProperties.__webglDepthbuffer[ i ];
                        _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

                    }

                }

            } else {

                const mipmaps = renderTarget.texture.mipmaps;

                if ( mipmaps && mipmaps.length > 0 ) {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] );

                } else {

                    state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );

                }

                if ( renderTargetProperties.__webglDepthbuffer === undefined ) {

                    renderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();
                    setupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );

                } else {

                    // attach buffer if it's been created already
                    const glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                    const renderbuffer = renderTargetProperties.__webglDepthbuffer;
                    _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );
                    _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );

                }

            }

        }

        state.bindFramebuffer( _gl.FRAMEBUFFER, null );

    }

disposeEvent(): void

Returns: void

Calls:

  • depthTexture.removeEventListener
Code
() => {

                    delete renderTargetProperties.__boundDepthTexture;
                    delete renderTargetProperties.__depthDisposeCallback;
                    depthTexture.removeEventListener( 'dispose', disposeEvent );

                }

rebindTextures(renderTarget: any, colorTexture: any, depthTexture: any): void

Parameters:

  • renderTarget any
  • colorTexture any
  • depthTexture any

Returns: void

Calls:

  • properties.get
  • setupFrameBufferTexture
  • setupDepthRenderbuffer
Code
function rebindTextures( renderTarget, colorTexture, depthTexture ) {

        const renderTargetProperties = properties.get( renderTarget );

        if ( colorTexture !== undefined ) {

            setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );

        }

        if ( depthTexture !== undefined ) {

            setupDepthRenderbuffer( renderTarget );

        }

    }

setupRenderTarget(renderTarget: any): void

Parameters:

  • renderTarget any

Returns: void

Calls:

  • properties.get
  • renderTarget.addEventListener
  • _gl.createTexture
  • _gl.createFramebuffer
  • useMultisampledRTT
  • state.bindFramebuffer
  • _gl.createRenderbuffer
  • _gl.bindRenderbuffer
  • utils.convert
  • getInternalFormat
  • getRenderTargetSamples
  • _gl.renderbufferStorageMultisample
  • _gl.framebufferRenderbuffer
  • setupRenderBufferStorage
  • state.bindTexture
  • setTextureParameters
  • setupFrameBufferTexture
  • textureNeedsGenerateMipmaps
  • generateMipmap
  • state.unbindTexture
  • setupDepthRenderbuffer

Internal Comments:

// Setup framebuffer
// Setup color buffer
// Setup depth and stencil buffers

Code
function setupRenderTarget( renderTarget ) {

        const texture = renderTarget.texture;

        const renderTargetProperties = properties.get( renderTarget );
        const textureProperties = properties.get( texture );

        renderTarget.addEventListener( 'dispose', onRenderTargetDispose );

        const textures = renderTarget.textures;

        const isCube = ( renderTarget.isWebGLCubeRenderTarget === true );
        const isMultipleRenderTargets = ( textures.length > 1 );

        if ( ! isMultipleRenderTargets ) {

            if ( textureProperties.__webglTexture === undefined ) {

                textureProperties.__webglTexture = _gl.createTexture();

            }

            textureProperties.__version = texture.version;
            info.memory.textures ++;

        }

        // Setup framebuffer

        if ( isCube ) {

            renderTargetProperties.__webglFramebuffer = [];

            for ( let i = 0; i < 6; i ++ ) {

                if ( 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 {

            if ( 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 ) {

                for ( let i = 0, il = textures.length; i < il; i ++ ) {

                    const attachmentProperties = properties.get( textures[ i ] );

                    if ( attachmentProperties.__webglTexture === undefined ) {

                        attachmentProperties.__webglTexture = _gl.createTexture();

                        info.memory.textures ++;

                    }

                }

            }

            if ( ( renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {

                renderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();
                renderTargetProperties.__webglColorRenderbuffer = [];

                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( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                    const glFormat = utils.convert( texture.format, texture.colorSpace );
                    const glType = utils.convert( texture.type );
                    const glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );
                    const samples = getRenderTargetSamples( renderTarget );
                    _gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );

                    _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                }

                _gl.bindRenderbuffer( _gl.RENDERBUFFER, null );

                if ( renderTarget.depthBuffer ) {

                    renderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();
                    setupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );

                }

                state.bindFramebuffer( _gl.FRAMEBUFFER, null );

            }

        }

        // Setup color buffer

        if ( isCube ) {

            state.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );
            setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );

            for ( let i = 0; i < 6; i ++ ) {

                if ( 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 ) ) {

                generateMipmap( _gl.TEXTURE_CUBE_MAP );

            }

            state.unbindTexture();

        } else if ( isMultipleRenderTargets ) {

            for ( let i = 0, il = textures.length; i < il; i ++ ) {

                const attachment = textures[ i ];
                const attachmentProperties = properties.get( attachment );

                let glTextureType = _gl.TEXTURE_2D;

                if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {

                    glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;

                }

                state.bindTexture( glTextureType, attachmentProperties.__webglTexture );
                setTextureParameters( glTextureType, attachment );
                setupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, glTextureType, 0 );

                if ( textureNeedsGenerateMipmaps( attachment ) ) {

                    generateMipmap( glTextureType );

                }

            }

            state.unbindTexture();

        } else {

            let glTextureType = _gl.TEXTURE_2D;

            if ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {

                glTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;

            }

            state.bindTexture( glTextureType, textureProperties.__webglTexture );
            setTextureParameters( glTextureType, texture );

            if ( 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 ) ) {

                generateMipmap( glTextureType );

            }

            state.unbindTexture();

        }

        // Setup depth and stencil buffers

        if ( renderTarget.depthBuffer ) {

            setupDepthRenderbuffer( renderTarget );

        }

    }

updateRenderTargetMipmap(renderTarget: any): void

Parameters:

  • renderTarget any

Returns: void

Calls:

  • textureNeedsGenerateMipmaps
  • getTargetType
  • properties.get
  • state.bindTexture
  • generateMipmap
  • state.unbindTexture
Code
function updateRenderTargetMipmap( renderTarget ) {

        const textures = renderTarget.textures;

        for ( let i = 0, il = textures.length; i < il; i ++ ) {

            const texture = textures[ i ];

            if ( textureNeedsGenerateMipmaps( texture ) ) {

                const targetType = getTargetType( renderTarget );
                const webglTexture = properties.get( texture ).__webglTexture;

                state.bindTexture( targetType, webglTexture );
                generateMipmap( targetType );
                state.unbindTexture();

            }

        }

    }

updateMultisampleRenderTarget(renderTarget: any): void

Parameters:

  • renderTarget any

Returns: void

Calls:

  • useMultisampledRTT
  • properties.get
  • state.bindFramebuffer
  • _gl.framebufferRenderbuffer
  • _gl.framebufferTexture2D
  • _gl.blitFramebuffer
  • invalidationArrayRead.push
  • invalidationArrayDraw.push
  • _gl.invalidateFramebuffer

Internal Comments:

// If MRT we need to remove FBO attachments
// resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)
// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments

Code
function updateMultisampleRenderTarget( renderTarget ) {

        if ( renderTarget.samples > 0 ) {

            if ( useMultisampledRTT( renderTarget ) === false ) {

                const textures = renderTarget.textures;
                const width = renderTarget.width;
                const height = renderTarget.height;
                let mask = _gl.COLOR_BUFFER_BIT;
                const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;
                const renderTargetProperties = properties.get( renderTarget );
                const isMultipleRenderTargets = ( textures.length > 1 );

                // If MRT we need to remove FBO attachments
                if ( isMultipleRenderTargets ) {

                    for ( let i = 0; i < textures.length; i ++ ) {

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );

                    }

                }

                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );

                const mipmaps = renderTarget.texture.mipmaps;

                if ( mipmaps && mipmaps.length > 0 ) {

                    state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ 0 ] );

                } else {

                    state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );

                }

                for ( let i = 0; i < textures.length; i ++ ) {

                    if ( renderTarget.resolveDepthBuffer ) {

                        if ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;

                        // resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)

                        if ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;

                    }

                    if ( isMultipleRenderTargets ) {

                        _gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                        const webglTexture = properties.get( textures[ i ] ).__webglTexture;
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );

                    }

                    _gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );

                    if ( supportsInvalidateFramebuffer === true ) {

                        invalidationArrayRead.length = 0;
                        invalidationArrayDraw.length = 0;

                        invalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i );

                        if ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false ) {

                            invalidationArrayRead.push( depthStyle );
                            invalidationArrayDraw.push( depthStyle );

                            _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, invalidationArrayDraw );

                        }

                        _gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArrayRead );

                    }

                }

                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( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );
                        _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );

                        const webglTexture = properties.get( textures[ i ] ).__webglTexture;

                        state.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );
                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );

                    }

                }

                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );

            } else {

                if ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer ) {

                    const depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;

                    _gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );

                }

            }

        }

    }

getRenderTargetSamples(renderTarget: any): number

Parameters:

  • renderTarget any

Returns: number

Calls:

  • Math.min
Code
function getRenderTargetSamples( renderTarget ) {

        return Math.min( capabilities.maxSamples, renderTarget.samples );

    }

useMultisampledRTT(renderTarget: any): boolean

Parameters:

  • renderTarget any

Returns: boolean

Calls:

  • properties.get
  • extensions.has
Code
function useMultisampledRTT( renderTarget ) {

        const renderTargetProperties = properties.get( renderTarget );

        return renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;

    }

updateVideoTexture(texture: any): void

Parameters:

  • texture any

Returns: void

Calls:

  • _videoTextures.get
  • _videoTextures.set
  • texture.update

Internal Comments:

// Check the last frame we updated the VideoTexture

Code
function updateVideoTexture( texture ) {

        const frame = info.render.frame;

        // Check the last frame we updated the VideoTexture

        if ( _videoTextures.get( texture ) !== frame ) {

            _videoTextures.set( texture, frame );
            texture.update();

        }

    }

verifyColorSpace(texture: any, image: any): any

Parameters:

  • texture any
  • image any

Returns: any

Calls:

  • ColorManagement.getTransfer
  • console.warn
  • console.error

Internal Comments:

// sRGB
// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format

Code
function verifyColorSpace( texture, image ) {

        const colorSpace = texture.colorSpace;
        const format = texture.format;
        const type = texture.type;

        if ( texture.isCompressedTexture === true || texture.isVideoTexture === true ) return image;

        if ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {

            // sRGB

            if ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {

                // in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format

                if ( format !== RGBAFormat || type !== UnsignedByteType ) {

                    console.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );

                }

            } else {

                console.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );

            }

        }

        return image;

    }

getDimensions(image: any): Vector2

Parameters:

  • image any

Returns: Vector2

Internal Comments:

// if intrinsic data are not available, fallback to width/height (x4)

Code
function getDimensions( image ) {

        if ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) {

            // if intrinsic data are not available, fallback to width/height

            _imageDimensions.width = image.naturalWidth || image.width;
            _imageDimensions.height = image.naturalHeight || image.height;

        } else if ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) {

            _imageDimensions.width = image.displayWidth;
            _imageDimensions.height = image.displayHeight;

        } else {

            _imageDimensions.width = image.width;
            _imageDimensions.height = image.height;

        }

        return _imageDimensions;

    }

WebGLUtils(gl: any, extensions: any): { convert: (p: any, colorSpace?: string) => any; }

Parameters:

  • gl any
  • extensions any

Returns: { convert: (p: any, colorSpace?: string) => any; }

Calls:

  • ColorManagement.getTransfer
  • extensions.get

Internal Comments:

// WebGL2 formats.
// S3TC
// PVRTC
// ETC
// ASTC
// BPTC
// RGTC
//
// if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)

Code
function WebGLUtils( gl, extensions ) {

    function convert( p, colorSpace = NoColorSpace ) {

        let extension;

        const transfer = ColorManagement.getTransfer( colorSpace );

        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 === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV;

        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 ) return gl.HALF_FLOAT;

        if ( p === AlphaFormat ) return gl.ALPHA;
        if ( p === RGBFormat ) return gl.RGB;
        if ( p === RGBAFormat ) return gl.RGBA;
        if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
        if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;

        // WebGL2 formats.

        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 ( transfer === SRGBTransfer ) {

                extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );

                if ( extension !== null ) {

                    if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
                    if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;

                } else {

                    return null;

                }

            } else {

                extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );

                if ( extension !== null ) {

                    if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
                    if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;

                } else {

                    return null;

                }

            }

        }

        // PVRTC

        if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );

            if ( extension !== null ) {

                if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
                if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
                if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
                if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;

            } else {

                return null;

            }

        }

        // ETC

        if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_etc' );

            if ( extension !== null ) {

                if ( p === RGB_ETC1_Format || 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 {

                return null;

            }

        }

        // ASTC

        if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
            p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
            p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
            p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
            p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_astc' );

            if ( extension !== null ) {

                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 {

                return null;

            }

        }

        // BPTC

        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 ( 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 {

                return null;

            }

        }

        //

        if ( p === UnsignedInt248Type ) return gl.UNSIGNED_INT_24_8;

        // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)

        return ( gl[ p ] !== undefined ) ? gl[ p ] : null;

    }

    return { convert: convert };

}

convert(p: any, colorSpace: string): any

Parameters:

  • p any
  • colorSpace string

Returns: any

Calls:

  • ColorManagement.getTransfer
  • extensions.get

Internal Comments:

// WebGL2 formats.
// S3TC
// PVRTC
// ETC
// ASTC
// BPTC
// RGTC
//
// if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)

Code
function convert( p, colorSpace = NoColorSpace ) {

        let extension;

        const transfer = ColorManagement.getTransfer( colorSpace );

        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 === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV;

        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 ) return gl.HALF_FLOAT;

        if ( p === AlphaFormat ) return gl.ALPHA;
        if ( p === RGBFormat ) return gl.RGB;
        if ( p === RGBAFormat ) return gl.RGBA;
        if ( p === DepthFormat ) return gl.DEPTH_COMPONENT;
        if ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;

        // WebGL2 formats.

        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 ( transfer === SRGBTransfer ) {

                extension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );

                if ( extension !== null ) {

                    if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
                    if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;

                } else {

                    return null;

                }

            } else {

                extension = extensions.get( 'WEBGL_compressed_texture_s3tc' );

                if ( extension !== null ) {

                    if ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;
                    if ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;
                    if ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;

                } else {

                    return null;

                }

            }

        }

        // PVRTC

        if ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );

            if ( extension !== null ) {

                if ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
                if ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
                if ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
                if ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;

            } else {

                return null;

            }

        }

        // ETC

        if ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_etc' );

            if ( extension !== null ) {

                if ( p === RGB_ETC1_Format || 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 {

                return null;

            }

        }

        // ASTC

        if ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||
            p === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||
            p === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||
            p === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||
            p === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {

            extension = extensions.get( 'WEBGL_compressed_texture_astc' );

            if ( extension !== null ) {

                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 {

                return null;

            }

        }

        // BPTC

        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 ( 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 {

                return null;

            }

        }

        //

        if ( p === UnsignedInt248Type ) return gl.UNSIGNED_INT_24_8;

        // if "p" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)

        return ( gl[ p ] !== undefined ) ? gl[ p ] : null;

    }

WebXRDepthSensing.init(depthData: XRWebGLDepthInformation, renderState: XRRenderState): void

JSDoc:

/**
     * Inits the depth sensing module
     *
     * @param {XRWebGLDepthInformation} depthData - The XR depth data.
     * @param {XRRenderState} renderState - The XR render state.
     */

Parameters:

  • depthData XRWebGLDepthInformation
  • renderState XRRenderState

Returns: void

Code
init( depthData, renderState ) {

        if ( this.texture === null ) {

            const texture = new ExternalTexture( depthData.texture );

            if ( ( depthData.depthNear !== renderState.depthNear ) || ( depthData.depthFar !== renderState.depthFar ) ) {

                this.depthNear = depthData.depthNear;
                this.depthFar = depthData.depthFar;

            }

            this.texture = texture;

        }

    }

WebXRDepthSensing.getMesh(cameraXR: ArrayCamera): Mesh

JSDoc:

/**
     * Returns a plane mesh that visualizes the depth texture.
     *
     * @param {ArrayCamera} cameraXR - The XR camera.
     * @return {?Mesh} The plane mesh.
     */

Parameters:

  • cameraXR ArrayCamera

Returns: Mesh

Code
getMesh( cameraXR ) {

        if ( this.texture !== null ) {

            if ( this.mesh === null ) {

                const viewport = cameraXR.cameras[ 0 ].viewport;
                const material = new ShaderMaterial( {
                    vertexShader: _occlusion_vertex,
                    fragmentShader: _occlusion_fragment,
                    uniforms: {
                        depthColor: { value: this.texture },
                        depthWidth: { value: viewport.z },
                        depthHeight: { value: viewport.w }
                    }
                } );

                this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material );

            }

        }

        return this.mesh;

    }

WebXRDepthSensing.reset(): void

JSDoc:

/**
     * Resets the module
     */

Returns: void

Code
reset() {

        this.texture = null;
        this.mesh = null;

    }

WebXRDepthSensing.getDepthTexture(): ExternalTexture

JSDoc:

/**
     * Returns a texture representing the depth of the user's environment.
     *
     * @return {?ExternalTexture} The depth texture.
     */

Returns: ExternalTexture

Code
getDepthTexture() {

        return this.texture;

    }

onSessionEvent(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • controllerInputSources.indexOf
  • controller.update
  • controller.dispatchEvent
Code
function onSessionEvent( event ) {

            const controllerIndex = controllerInputSources.indexOf( event.inputSource );

            if ( controllerIndex === -1 ) {

                return;

            }

            const controller = controllers[ controllerIndex ];

            if ( controller !== undefined ) {

                controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );
                controller.dispatchEvent( { type: event.type, data: event.inputSource } );

            }

        }

onSessionEnd(): void

Returns: void

Calls:

  • session.removeEventListener
  • controllers[ i ].disconnect
  • depthSensing.reset
  • renderer.setRenderTarget
  • animation.stop
  • renderer.setPixelRatio
  • renderer.setSize
  • scope.dispatchEvent

Internal Comments:

// restore framebuffer/rendering state (x4)
// (x4)

Code
function onSessionEnd() {

            session.removeEventListener( 'select', onSessionEvent );
            session.removeEventListener( 'selectstart', onSessionEvent );
            session.removeEventListener( 'selectend', onSessionEvent );
            session.removeEventListener( 'squeeze', onSessionEvent );
            session.removeEventListener( 'squeezestart', onSessionEvent );
            session.removeEventListener( 'squeezeend', onSessionEvent );
            session.removeEventListener( 'end', onSessionEnd );
            session.removeEventListener( 'inputsourceschange', onInputSourcesChange );

            for ( let i = 0; i < controllers.length; i ++ ) {

                const inputSource = controllerInputSources[ i ];

                if ( inputSource === null ) continue;

                controllerInputSources[ i ] = null;

                controllers[ i ].disconnect( inputSource );

            }

            _currentDepthNear = null;
            _currentDepthFar = null;

            depthSensing.reset();
            for ( const key in cameraAccessTextures ) {

                delete cameraAccessTextures[ key ];

            }

            // restore framebuffer/rendering state

            renderer.setRenderTarget( initialRenderTarget );

            glBaseLayer = null;
            glProjLayer = null;
            glBinding = null;
            session = null;
            newRenderTarget = null;

            //

            animation.stop();

            scope.isPresenting = false;

            renderer.setPixelRatio( currentPixelRatio );
            renderer.setSize( currentSize.width, currentSize.height, false );

            scope.dispatchEvent( { type: 'sessionend' } );

        }

onInputSourcesChange(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • controllerInputSources.indexOf
  • controllers[ index ].disconnect
  • controllerInputSources.push
  • controller.connect

Internal Comments:

// Notify disconnected
// Notify connected
// Assign input source a controller that currently has no input source
// If all controllers do currently receive input we ignore new ones

Code
function onInputSourcesChange( event ) {

            // Notify disconnected

            for ( let i = 0; i < event.removed.length; i ++ ) {

                const inputSource = event.removed[ i ];
                const index = controllerInputSources.indexOf( inputSource );

                if ( index >= 0 ) {

                    controllerInputSources[ index ] = null;
                    controllers[ index ].disconnect( inputSource );

                }

            }

            // Notify connected

            for ( let i = 0; i < event.added.length; i ++ ) {

                const inputSource = event.added[ i ];

                let controllerIndex = controllerInputSources.indexOf( inputSource );

                if ( controllerIndex === -1 ) {

                    // Assign input source a controller that currently has no input source

                    for ( let i = 0; i < controllers.length; i ++ ) {

                        if ( i >= controllerInputSources.length ) {

                            controllerInputSources.push( inputSource );
                            controllerIndex = i;
                            break;

                        } else if ( controllerInputSources[ i ] === null ) {

                            controllerInputSources[ i ] = inputSource;
                            controllerIndex = i;
                            break;

                        }

                    }

                    // If all controllers do currently receive input we ignore new ones

                    if ( controllerIndex === -1 ) break;

                }

                const controller = controllers[ controllerIndex ];

                if ( controller ) {

                    controller.connect( inputSource );

                }

            }

        }

setProjectionFromUnion(camera: ArrayCamera, cameraL: PerspectiveCamera, cameraR: PerspectiveCamera): void

JSDoc:

/**
         * Assumes 2 cameras that are parallel and share an X-axis, and that
         * the cameras' projection and world matrices have already been set.
         * And that near and far planes are identical for both cameras.
         * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
         *
         * @param {ArrayCamera} camera - The camera to update.
         * @param {PerspectiveCamera} cameraL - The left camera.
         * @param {PerspectiveCamera} cameraR - The right camera.
         */

Parameters:

  • camera ArrayCamera
  • cameraL PerspectiveCamera
  • cameraR PerspectiveCamera

Returns: void

Calls:

  • cameraLPos.setFromMatrixPosition
  • cameraRPos.setFromMatrixPosition
  • cameraLPos.distanceTo
  • cameraL.matrixWorld.decompose
  • camera.translateX
  • camera.translateZ
  • camera.matrixWorld.compose
  • camera.matrixWorldInverse.copy( camera.matrixWorld ).invert
  • camera.projectionMatrix.copy
  • camera.projectionMatrixInverse.copy
  • camera.projectionMatrix.makePerspective
  • camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert

Internal Comments:

// VR systems will have identical far and near planes, and (x2)
// most likely identical top and bottom frustum extents. (x2)
// Use the left camera for these values. (x2)
// Calculate the new camera's position offset from the (x2)
// left camera. xOffset should be roughly half `ipd`. (x2)
// TODO: Better way to apply this offset? (x5)
// Check if the projection uses an infinite far plane.
// Use the projection matrix from the left eye. (x5)
// The camera offset is sufficient to include the view volumes (x5)
// of both eyes (assuming symmetric projections). (x5)
// Find the union of the frustum values of the cameras and scale (x2)
// the values so that the near plane's position does not change in world space, (x2)
// although must now be relative to the new union camera. (x2)

Code
function setProjectionFromUnion( camera, cameraL, cameraR ) {

            cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
            cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );

            const ipd = cameraLPos.distanceTo( cameraRPos );

            const projL = cameraL.projectionMatrix.elements;
            const projR = cameraR.projectionMatrix.elements;

            // VR systems will have identical far and near planes, and
            // most likely identical top and bottom frustum extents.
            // Use the left camera for these values.
            const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
            const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
            const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
            const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];

            const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
            const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
            const left = near * leftFov;
            const right = near * rightFov;

            // Calculate the new camera's position offset from the
            // left camera. xOffset should be roughly half `ipd`.
            const zOffset = ipd / ( - leftFov + rightFov );
            const xOffset = zOffset * - leftFov;

            // TODO: Better way to apply this offset?
            cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
            camera.translateX( xOffset );
            camera.translateZ( zOffset );
            camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
            camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();

            // Check if the projection uses an infinite far plane.
            if ( projL[ 10 ] === -1 ) {

                // Use the projection matrix from the left eye.
                // The camera offset is sufficient to include the view volumes
                // of both eyes (assuming symmetric projections).
                camera.projectionMatrix.copy( cameraL.projectionMatrix );
                camera.projectionMatrixInverse.copy( cameraL.projectionMatrixInverse );

            } else {

                // Find the union of the frustum values of the cameras and scale
                // the values so that the near plane's position does not change in world space,
                // although must now be relative to the new union camera.
                const near2 = near + zOffset;
                const far2 = far + zOffset;
                const left2 = left - xOffset;
                const right2 = right + ( ipd - xOffset );
                const top2 = topFov * far / far2 * near2;
                const bottom2 = bottomFov * far / far2 * near2;

                camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
                camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();

            }

        }

updateCamera(camera: any, parent: any): void

Parameters:

  • camera any
  • parent any

Returns: void

Calls:

  • camera.matrixWorld.copy
  • camera.matrixWorld.multiplyMatrices
  • camera.matrixWorldInverse.copy( camera.matrixWorld ).invert
Code
function updateCamera( camera, parent ) {

            if ( parent === null ) {

                camera.matrixWorld.copy( camera.matrix );

            } else {

                camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );

            }

            camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();

        }

updateUserCamera(camera: any, cameraXR: any, parent: any): void

Parameters:

  • camera any
  • cameraXR any
  • parent any

Returns: void

Calls:

  • camera.matrix.copy
  • camera.matrix.invert
  • camera.matrix.multiply
  • camera.matrix.decompose
  • camera.updateMatrixWorld
  • camera.projectionMatrix.copy
  • camera.projectionMatrixInverse.copy
  • Math.atan
Code
function updateUserCamera( camera, cameraXR, parent ) {

            if ( parent === null ) {

                camera.matrix.copy( cameraXR.matrixWorld );

            } else {

                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 );

            if ( camera.isPerspectiveCamera ) {

                camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
                camera.zoom = 1;

            }

        }

onAnimationFrame(time: any, frame: any): void

Parameters:

  • time any
  • frame any

Returns: void

Calls:

  • frame.getViewerPose
  • renderer.setRenderTargetFramebuffer
  • renderer.setRenderTarget
  • glBaseLayer.getViewport
  • glBinding.getViewSubImage
  • renderer.setRenderTargetTextures
  • camera.layers.enable
  • camera.matrix.fromArray
  • camera.matrix.decompose
  • camera.projectionMatrix.fromArray
  • camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert
  • camera.viewport.set
  • cameraXR.matrix.copy
  • cameraXR.matrix.decompose
  • cameraXR.cameras.push
  • enabledFeatures.includes
  • glBinding.getDepthInformation
  • depthSensing.init
  • renderer.state.unbindTexture
  • glBinding.getCameraImage
  • controller.update
  • onAnimationFrameCallback
  • scope.dispatchEvent

Internal Comments:

// check if it's necessary to rebuild cameraXR's camera list
// For side-by-side projection, we only produce a single texture for both eyes.
// (x3)

Code
function onAnimationFrame( time, frame ) {

            pose = frame.getViewerPose( customReferenceSpace || referenceSpace );
            xrFrame = frame;

            if ( pose !== null ) {

                const views = pose.views;

                if ( glBaseLayer !== null ) {

                    renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
                    renderer.setRenderTarget( newRenderTarget );

                }

                let cameraXRNeedsUpdate = false;

                // check if it's necessary to rebuild cameraXR's camera list

                if ( views.length !== cameraXR.cameras.length ) {

                    cameraXR.cameras.length = 0;
                    cameraXRNeedsUpdate = true;

                }

                for ( let i = 0; i < views.length; i ++ ) {

                    const view = views[ i ];

                    let viewport = null;

                    if ( glBaseLayer !== null ) {

                        viewport = glBaseLayer.getViewport( view );

                    } else {

                        const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
                        viewport = glSubImage.viewport;

                        // For side-by-side projection, we only produce a single texture for both eyes.
                        if ( i === 0 ) {

                            renderer.setRenderTargetTextures(
                                newRenderTarget,
                                glSubImage.colorTexture,
                                glSubImage.depthStencilTexture );

                            renderer.setRenderTarget( newRenderTarget );

                        }

                    }

                    let camera = cameras[ i ];

                    if ( camera === undefined ) {

                        camera = new PerspectiveCamera();
                        camera.layers.enable( i );
                        camera.viewport = new Vector4();
                        cameras[ i ] = camera;

                    }

                    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 ) {

                        cameraXR.matrix.copy( camera.matrix );
                        cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );

                    }

                    if ( cameraXRNeedsUpdate === true ) {

                        cameraXR.cameras.push( camera );

                    }

                }

                //

                const enabledFeatures = session.enabledFeatures;
                const gpuDepthSensingEnabled = enabledFeatures &&
                    enabledFeatures.includes( 'depth-sensing' ) &&
                    session.depthUsage == 'gpu-optimized';

                if ( gpuDepthSensingEnabled && glBinding ) {

                    const depthData = glBinding.getDepthInformation( views[ 0 ] );

                    if ( depthData && depthData.isValid && depthData.texture ) {

                        depthSensing.init( depthData, session.renderState );

                    }

                }

                const cameraAccessEnabled = enabledFeatures &&
                    enabledFeatures.includes( 'camera-access' );

                if ( cameraAccessEnabled ) {

                    renderer.state.unbindTexture();

                    if ( glBinding ) {

                        for ( let i = 0; i < views.length; i ++ ) {

                            const camera = views[ i ].camera;

                            if ( camera ) {

                                let cameraTex = cameraAccessTextures[ camera ];

                                if ( ! cameraTex ) {

                                    cameraTex = new ExternalTexture();
                                    cameraAccessTextures[ camera ] = cameraTex;

                                }

                                const glTexture = glBinding.getCameraImage( camera );
                                cameraTex.sourceTexture = glTexture;

                            }

                        }

                    }

                }

            }

            //

            for ( let i = 0; i < controllers.length; i ++ ) {

                const inputSource = controllerInputSources[ i ];
                const controller = controllers[ i ];

                if ( inputSource !== null && controller !== undefined ) {

                    controller.update( inputSource, frame, customReferenceSpace || referenceSpace );

                }

            }

            if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );

            if ( frame.detectedPlanes ) {

                scope.dispatchEvent( { type: 'planesdetected', data: frame } );

            }

            xrFrame = null;

        }

WebGLMaterials(renderer: any, properties: any): { refreshFogUniforms: (uniforms: any, fog: any) => void; refreshMaterialUniforms: (uniforms: any, material: any, pixelRatio: any, height: any, transmissionRenderTarget: any) => void; }

Parameters:

  • renderer any
  • properties any

Returns: { refreshFogUniforms: (uniforms: any, fog: any) => void; refreshMaterialUniforms: (uniforms: any, material: any, pixelRatio: any, height: any, transmissionRenderTarget: any) => void; }

Calls:

  • map.updateMatrix
  • uniform.value.copy
  • fog.color.getRGB
  • getUnlitUniformColorSpace (from ./three.core.js)
  • refreshUniformsCommon
  • refreshUniformsToon
  • refreshUniformsPhong
  • refreshUniformsStandard
  • refreshUniformsPhysical
  • refreshUniformsMatcap
  • refreshUniformsDistance
  • refreshUniformsLine
  • refreshUniformsDash
  • refreshUniformsPoints
  • refreshUniformsSprites
  • uniforms.color.value.copy
  • uniforms.diffuse.value.copy
  • uniforms.emissive.value.copy( material.emissive ).multiplyScalar
  • refreshTransformUniform
  • uniforms.normalScale.value.copy
  • uniforms.normalScale.value.negate
  • properties.get
  • _e1.copy
  • uniforms.envMapRotation.value.setFromMatrix4
  • _m1.makeRotationFromEuler
  • uniforms.specular.value.copy
  • Math.max
  • uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar
  • uniforms.clearcoatNormalScale.value.copy
  • uniforms.clearcoatNormalScale.value.negate
  • uniforms.transmissionSamplerSize.value.set
  • uniforms.attenuationColor.value.copy
  • uniforms.anisotropyVector.value.set
  • Math.cos
  • Math.sin
  • uniforms.specularColor.value.copy
  • uniforms.referencePosition.value.setFromMatrixPosition

Internal Comments:

// accommodate left-handed frame (x4)
// environment maps which are not cube render targets or PMREMs follow a different convention (x4)
//uniforms.envMap.value = material.envMap; // part of uniforms common (x5)

Code
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 ) );

        if ( fog.isFog ) {

            uniforms.fogNear.value = fog.near;
            uniforms.fogFar.value = fog.far;

        } else if ( fog.isFogExp2 ) {

            uniforms.fogDensity.value = fog.density;

        }

    }

    function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {

        if ( material.isMeshBasicMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshLambertMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshToonMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsToon( uniforms, material );

        } else if ( material.isMeshPhongMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsPhong( uniforms, material );

        } else if ( material.isMeshStandardMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsStandard( uniforms, material );

            if ( material.isMeshPhysicalMaterial ) {

                refreshUniformsPhysical( uniforms, material, transmissionRenderTarget );

            }

        } else if ( material.isMeshMatcapMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsMatcap( uniforms, material );

        } else if ( material.isMeshDepthMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshDistanceMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsDistance( uniforms, material );

        } else if ( material.isMeshNormalMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isLineBasicMaterial ) {

            refreshUniformsLine( uniforms, material );

            if ( material.isLineDashedMaterial ) {

                refreshUniformsDash( uniforms, material );

            }

        } else if ( material.isPointsMaterial ) {

            refreshUniformsPoints( uniforms, material, pixelRatio, height );

        } else if ( material.isSpriteMaterial ) {

            refreshUniformsSprites( uniforms, material );

        } else if ( material.isShadowMaterial ) {

            uniforms.color.value.copy( material.color );
            uniforms.opacity.value = material.opacity;

        } else if ( material.isShaderMaterial ) {

            material.uniformsNeedUpdate = false; // #15581

        }

    }

    function refreshUniformsCommon( uniforms, material ) {

        uniforms.opacity.value = material.opacity;

        if ( material.color ) {

            uniforms.diffuse.value.copy( material.color );

        }

        if ( material.emissive ) {

            uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );

        }

        if ( material.map ) {

            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.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;

        }

        if ( material.emissiveMap ) {

            uniforms.emissiveMap.value = material.emissiveMap;

            refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );

        }

        if ( material.specularMap ) {

            uniforms.specularMap.value = material.specularMap;

            refreshTransformUniform( material.specularMap, uniforms.specularMapTransform );

        }

        if ( material.alphaTest > 0 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

        const materialProperties = properties.get( material );

        const envMap = materialProperties.envMap;
        const envMapRotation = materialProperties.envMapRotation;

        if ( envMap ) {

            uniforms.envMap.value = envMap;

            _e1.copy( envMapRotation );

            // accommodate left-handed frame
            _e1.x *= -1; _e1.y *= -1; _e1.z *= -1;

            if ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) {

                // environment maps which are not cube render targets or PMREMs follow a different convention
                _e1.y *= -1;
                _e1.z *= -1;

            }

            uniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( _e1 ) );

            uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? -1 : 1;

            uniforms.reflectivity.value = material.reflectivity;
            uniforms.ior.value = material.ior;
            uniforms.refractionRatio.value = material.refractionRatio;

        }

        if ( material.lightMap ) {

            uniforms.lightMap.value = material.lightMap;
            uniforms.lightMapIntensity.value = material.lightMapIntensity;

            refreshTransformUniform( material.lightMap, uniforms.lightMapTransform );

        }

        if ( material.aoMap ) {

            uniforms.aoMap.value = material.aoMap;
            uniforms.aoMapIntensity.value = material.aoMapIntensity;

            refreshTransformUniform( material.aoMap, uniforms.aoMapTransform );

        }

    }

    function refreshUniformsLine( uniforms, material ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;

        if ( material.map ) {

            uniforms.map.value = material.map;

            refreshTransformUniform( material.map, uniforms.mapTransform );

        }

    }

    function refreshUniformsDash( uniforms, material ) {

        uniforms.dashSize.value = material.dashSize;
        uniforms.totalSize.value = material.dashSize + material.gapSize;
        uniforms.scale.value = material.scale;

    }

    function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;
        uniforms.size.value = material.size * pixelRatio;
        uniforms.scale.value = height * 0.5;

        if ( material.map ) {

            uniforms.map.value = material.map;

            refreshTransformUniform( material.map, uniforms.uvTransform );

        }

        if ( material.alphaMap ) {

            uniforms.alphaMap.value = material.alphaMap;

            refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );

        }

        if ( material.alphaTest > 0 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

    }

    function refreshUniformsSprites( uniforms, material ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;
        uniforms.rotation.value = material.rotation;

        if ( material.map ) {

            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 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

    }

    function refreshUniformsPhong( uniforms, material ) {

        uniforms.specular.value.copy( material.specular );
        uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )

    }

    function refreshUniformsToon( uniforms, material ) {

        if ( material.gradientMap ) {

            uniforms.gradientMap.value = material.gradientMap;

        }

    }

    function refreshUniformsStandard( uniforms, material ) {

        uniforms.metalness.value = material.metalness;

        if ( material.metalnessMap ) {

            uniforms.metalnessMap.value = material.metalnessMap;

            refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );

        }

        uniforms.roughness.value = material.roughness;

        if ( material.roughnessMap ) {

            uniforms.roughnessMap.value = material.roughnessMap;

            refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );

        }

        if ( material.envMap ) {

            //uniforms.envMap.value = material.envMap; // part of uniforms common

            uniforms.envMapIntensity.value = material.envMapIntensity;

        }

    }

    function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {

        uniforms.ior.value = material.ior; // also part of uniforms common

        if ( material.sheen > 0 ) {

            uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );

            uniforms.sheenRoughness.value = material.sheenRoughness;

            if ( material.sheenColorMap ) {

                uniforms.sheenColorMap.value = material.sheenColorMap;

                refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );

            }

            if ( material.sheenRoughnessMap ) {

                uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;

                refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );

            }

        }

        if ( material.clearcoat > 0 ) {

            uniforms.clearcoat.value = material.clearcoat;
            uniforms.clearcoatRoughness.value = material.clearcoatRoughness;

            if ( material.clearcoatMap ) {

                uniforms.clearcoatMap.value = material.clearcoatMap;

                refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );

            }

            if ( material.clearcoatRoughnessMap ) {

                uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;

                refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );

            }

            if ( material.clearcoatNormalMap ) {

                uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;

                refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );

                uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );

                if ( material.side === BackSide ) {

                    uniforms.clearcoatNormalScale.value.negate();

                }

            }

        }

        if ( material.dispersion > 0 ) {

            uniforms.dispersion.value = material.dispersion;

        }

        if ( material.iridescence > 0 ) {

            uniforms.iridescence.value = material.iridescence;
            uniforms.iridescenceIOR.value = material.iridescenceIOR;
            uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];
            uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];

            if ( material.iridescenceMap ) {

                uniforms.iridescenceMap.value = material.iridescenceMap;

                refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );

            }

            if ( material.iridescenceThicknessMap ) {

                uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;

                refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );

            }

        }

        if ( material.transmission > 0 ) {

            uniforms.transmission.value = material.transmission;
            uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
            uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );

            if ( material.transmissionMap ) {

                uniforms.transmissionMap.value = material.transmissionMap;

                refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );

            }

            uniforms.thickness.value = material.thickness;

            if ( material.thicknessMap ) {

                uniforms.thicknessMap.value = material.thicknessMap;

                refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );

            }

            uniforms.attenuationDistance.value = material.attenuationDistance;
            uniforms.attenuationColor.value.copy( material.attenuationColor );

        }

        if ( material.anisotropy > 0 ) {

            uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );

            if ( material.anisotropyMap ) {

                uniforms.anisotropyMap.value = material.anisotropyMap;

                refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );

            }

        }

        uniforms.specularIntensity.value = material.specularIntensity;
        uniforms.specularColor.value.copy( material.specularColor );

        if ( material.specularColorMap ) {

            uniforms.specularColorMap.value = material.specularColorMap;

            refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );

        }

        if ( material.specularIntensityMap ) {

            uniforms.specularIntensityMap.value = material.specularIntensityMap;

            refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );

        }

    }

    function refreshUniformsMatcap( uniforms, material ) {

        if ( material.matcap ) {

            uniforms.matcap.value = material.matcap;

        }

    }

    function refreshUniformsDistance( uniforms, material ) {

        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;

    }

    return {
        refreshFogUniforms: refreshFogUniforms,
        refreshMaterialUniforms: refreshMaterialUniforms
    };

}

refreshTransformUniform(map: any, uniform: any): void

Parameters:

  • map any
  • uniform any

Returns: void

Calls:

  • map.updateMatrix
  • uniform.value.copy
Code
function refreshTransformUniform( map, uniform ) {

        if ( map.matrixAutoUpdate === true ) {

            map.updateMatrix();

        }

        uniform.value.copy( map.matrix );

    }

refreshFogUniforms(uniforms: any, fog: any): void

Parameters:

  • uniforms any
  • fog any

Returns: void

Calls:

  • fog.color.getRGB
  • getUnlitUniformColorSpace (from ./three.core.js)
Code
function refreshFogUniforms( uniforms, fog ) {

        fog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );

        if ( fog.isFog ) {

            uniforms.fogNear.value = fog.near;
            uniforms.fogFar.value = fog.far;

        } else if ( fog.isFogExp2 ) {

            uniforms.fogDensity.value = fog.density;

        }

    }

refreshMaterialUniforms(uniforms: any, material: any, pixelRatio: any, height: any, transmissionRenderTarget: any): void

Parameters:

  • uniforms any
  • material any
  • pixelRatio any
  • height any
  • transmissionRenderTarget any

Returns: void

Calls:

  • refreshUniformsCommon
  • refreshUniformsToon
  • refreshUniformsPhong
  • refreshUniformsStandard
  • refreshUniformsPhysical
  • refreshUniformsMatcap
  • refreshUniformsDistance
  • refreshUniformsLine
  • refreshUniformsDash
  • refreshUniformsPoints
  • refreshUniformsSprites
  • uniforms.color.value.copy
Code
function refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {

        if ( material.isMeshBasicMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshLambertMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshToonMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsToon( uniforms, material );

        } else if ( material.isMeshPhongMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsPhong( uniforms, material );

        } else if ( material.isMeshStandardMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsStandard( uniforms, material );

            if ( material.isMeshPhysicalMaterial ) {

                refreshUniformsPhysical( uniforms, material, transmissionRenderTarget );

            }

        } else if ( material.isMeshMatcapMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsMatcap( uniforms, material );

        } else if ( material.isMeshDepthMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isMeshDistanceMaterial ) {

            refreshUniformsCommon( uniforms, material );
            refreshUniformsDistance( uniforms, material );

        } else if ( material.isMeshNormalMaterial ) {

            refreshUniformsCommon( uniforms, material );

        } else if ( material.isLineBasicMaterial ) {

            refreshUniformsLine( uniforms, material );

            if ( material.isLineDashedMaterial ) {

                refreshUniformsDash( uniforms, material );

            }

        } else if ( material.isPointsMaterial ) {

            refreshUniformsPoints( uniforms, material, pixelRatio, height );

        } else if ( material.isSpriteMaterial ) {

            refreshUniformsSprites( uniforms, material );

        } else if ( material.isShadowMaterial ) {

            uniforms.color.value.copy( material.color );
            uniforms.opacity.value = material.opacity;

        } else if ( material.isShaderMaterial ) {

            material.uniformsNeedUpdate = false; // #15581

        }

    }

refreshUniformsCommon(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • uniforms.diffuse.value.copy
  • uniforms.emissive.value.copy( material.emissive ).multiplyScalar
  • refreshTransformUniform
  • uniforms.normalScale.value.copy
  • uniforms.normalScale.value.negate
  • properties.get
  • _e1.copy
  • uniforms.envMapRotation.value.setFromMatrix4
  • _m1.makeRotationFromEuler

Internal Comments:

// accommodate left-handed frame (x4)
// environment maps which are not cube render targets or PMREMs follow a different convention (x4)

Code
function refreshUniformsCommon( uniforms, material ) {

        uniforms.opacity.value = material.opacity;

        if ( material.color ) {

            uniforms.diffuse.value.copy( material.color );

        }

        if ( material.emissive ) {

            uniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );

        }

        if ( material.map ) {

            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.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;

        }

        if ( material.emissiveMap ) {

            uniforms.emissiveMap.value = material.emissiveMap;

            refreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );

        }

        if ( material.specularMap ) {

            uniforms.specularMap.value = material.specularMap;

            refreshTransformUniform( material.specularMap, uniforms.specularMapTransform );

        }

        if ( material.alphaTest > 0 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

        const materialProperties = properties.get( material );

        const envMap = materialProperties.envMap;
        const envMapRotation = materialProperties.envMapRotation;

        if ( envMap ) {

            uniforms.envMap.value = envMap;

            _e1.copy( envMapRotation );

            // accommodate left-handed frame
            _e1.x *= -1; _e1.y *= -1; _e1.z *= -1;

            if ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) {

                // environment maps which are not cube render targets or PMREMs follow a different convention
                _e1.y *= -1;
                _e1.z *= -1;

            }

            uniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( _e1 ) );

            uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? -1 : 1;

            uniforms.reflectivity.value = material.reflectivity;
            uniforms.ior.value = material.ior;
            uniforms.refractionRatio.value = material.refractionRatio;

        }

        if ( material.lightMap ) {

            uniforms.lightMap.value = material.lightMap;
            uniforms.lightMapIntensity.value = material.lightMapIntensity;

            refreshTransformUniform( material.lightMap, uniforms.lightMapTransform );

        }

        if ( material.aoMap ) {

            uniforms.aoMap.value = material.aoMap;
            uniforms.aoMapIntensity.value = material.aoMapIntensity;

            refreshTransformUniform( material.aoMap, uniforms.aoMapTransform );

        }

    }

refreshUniformsLine(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • uniforms.diffuse.value.copy
  • refreshTransformUniform
Code
function refreshUniformsLine( uniforms, material ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;

        if ( material.map ) {

            uniforms.map.value = material.map;

            refreshTransformUniform( material.map, uniforms.mapTransform );

        }

    }

refreshUniformsDash(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Code
function refreshUniformsDash( uniforms, material ) {

        uniforms.dashSize.value = material.dashSize;
        uniforms.totalSize.value = material.dashSize + material.gapSize;
        uniforms.scale.value = material.scale;

    }

refreshUniformsPoints(uniforms: any, material: any, pixelRatio: any, height: any): void

Parameters:

  • uniforms any
  • material any
  • pixelRatio any
  • height any

Returns: void

Calls:

  • uniforms.diffuse.value.copy
  • refreshTransformUniform
Code
function refreshUniformsPoints( uniforms, material, pixelRatio, height ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;
        uniforms.size.value = material.size * pixelRatio;
        uniforms.scale.value = height * 0.5;

        if ( material.map ) {

            uniforms.map.value = material.map;

            refreshTransformUniform( material.map, uniforms.uvTransform );

        }

        if ( material.alphaMap ) {

            uniforms.alphaMap.value = material.alphaMap;

            refreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );

        }

        if ( material.alphaTest > 0 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

    }

refreshUniformsSprites(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • uniforms.diffuse.value.copy
  • refreshTransformUniform
Code
function refreshUniformsSprites( uniforms, material ) {

        uniforms.diffuse.value.copy( material.color );
        uniforms.opacity.value = material.opacity;
        uniforms.rotation.value = material.rotation;

        if ( material.map ) {

            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 ) {

            uniforms.alphaTest.value = material.alphaTest;

        }

    }

refreshUniformsPhong(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • uniforms.specular.value.copy
  • Math.max
Code
function refreshUniformsPhong( uniforms, material ) {

        uniforms.specular.value.copy( material.specular );
        uniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )

    }

refreshUniformsToon(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Code
function refreshUniformsToon( uniforms, material ) {

        if ( material.gradientMap ) {

            uniforms.gradientMap.value = material.gradientMap;

        }

    }

refreshUniformsStandard(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • refreshTransformUniform

Internal Comments:

//uniforms.envMap.value = material.envMap; // part of uniforms common (x5)

Code
function refreshUniformsStandard( uniforms, material ) {

        uniforms.metalness.value = material.metalness;

        if ( material.metalnessMap ) {

            uniforms.metalnessMap.value = material.metalnessMap;

            refreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );

        }

        uniforms.roughness.value = material.roughness;

        if ( material.roughnessMap ) {

            uniforms.roughnessMap.value = material.roughnessMap;

            refreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );

        }

        if ( material.envMap ) {

            //uniforms.envMap.value = material.envMap; // part of uniforms common

            uniforms.envMapIntensity.value = material.envMapIntensity;

        }

    }

refreshUniformsPhysical(uniforms: any, material: any, transmissionRenderTarget: any): void

Parameters:

  • uniforms any
  • material any
  • transmissionRenderTarget any

Returns: void

Calls:

  • uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar
  • refreshTransformUniform
  • uniforms.clearcoatNormalScale.value.copy
  • uniforms.clearcoatNormalScale.value.negate
  • uniforms.transmissionSamplerSize.value.set
  • uniforms.attenuationColor.value.copy
  • uniforms.anisotropyVector.value.set
  • Math.cos
  • Math.sin
  • uniforms.specularColor.value.copy
Code
function refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {

        uniforms.ior.value = material.ior; // also part of uniforms common

        if ( material.sheen > 0 ) {

            uniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );

            uniforms.sheenRoughness.value = material.sheenRoughness;

            if ( material.sheenColorMap ) {

                uniforms.sheenColorMap.value = material.sheenColorMap;

                refreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );

            }

            if ( material.sheenRoughnessMap ) {

                uniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;

                refreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );

            }

        }

        if ( material.clearcoat > 0 ) {

            uniforms.clearcoat.value = material.clearcoat;
            uniforms.clearcoatRoughness.value = material.clearcoatRoughness;

            if ( material.clearcoatMap ) {

                uniforms.clearcoatMap.value = material.clearcoatMap;

                refreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );

            }

            if ( material.clearcoatRoughnessMap ) {

                uniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;

                refreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );

            }

            if ( material.clearcoatNormalMap ) {

                uniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;

                refreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );

                uniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );

                if ( material.side === BackSide ) {

                    uniforms.clearcoatNormalScale.value.negate();

                }

            }

        }

        if ( material.dispersion > 0 ) {

            uniforms.dispersion.value = material.dispersion;

        }

        if ( material.iridescence > 0 ) {

            uniforms.iridescence.value = material.iridescence;
            uniforms.iridescenceIOR.value = material.iridescenceIOR;
            uniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];
            uniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];

            if ( material.iridescenceMap ) {

                uniforms.iridescenceMap.value = material.iridescenceMap;

                refreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );

            }

            if ( material.iridescenceThicknessMap ) {

                uniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;

                refreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );

            }

        }

        if ( material.transmission > 0 ) {

            uniforms.transmission.value = material.transmission;
            uniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;
            uniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );

            if ( material.transmissionMap ) {

                uniforms.transmissionMap.value = material.transmissionMap;

                refreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );

            }

            uniforms.thickness.value = material.thickness;

            if ( material.thicknessMap ) {

                uniforms.thicknessMap.value = material.thicknessMap;

                refreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );

            }

            uniforms.attenuationDistance.value = material.attenuationDistance;
            uniforms.attenuationColor.value.copy( material.attenuationColor );

        }

        if ( material.anisotropy > 0 ) {

            uniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );

            if ( material.anisotropyMap ) {

                uniforms.anisotropyMap.value = material.anisotropyMap;

                refreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );

            }

        }

        uniforms.specularIntensity.value = material.specularIntensity;
        uniforms.specularColor.value.copy( material.specularColor );

        if ( material.specularColorMap ) {

            uniforms.specularColorMap.value = material.specularColorMap;

            refreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );

        }

        if ( material.specularIntensityMap ) {

            uniforms.specularIntensityMap.value = material.specularIntensityMap;

            refreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );

        }

    }

refreshUniformsMatcap(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Code
function refreshUniformsMatcap( uniforms, material ) {

        if ( material.matcap ) {

            uniforms.matcap.value = material.matcap;

        }

    }

refreshUniformsDistance(uniforms: any, material: any): void

Parameters:

  • uniforms any
  • material any

Returns: void

Calls:

  • properties.get
  • uniforms.referencePosition.value.setFromMatrixPosition
Code
function refreshUniformsDistance( uniforms, material ) {

        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;

    }

WebGLUniformsGroups(gl: any, info: any, capabilities: any, state: any): { bind: (uniformsGroup: any, program: any) => void; update: (uniformsGroup: any, program: any) => void; dispose: () => void; }

Parameters:

  • gl any
  • info any
  • capabilities any
  • state any

Returns: { bind: (uniformsGroup: any, program: any) => void; update: (uniformsGroup: any, program: any) => void; dispose: () => void; }

Calls:

  • gl.getParameter
  • state.uniformBlockBinding
  • prepareUniformsGroup
  • createBuffer
  • uniformsGroup.addEventListener
  • state.updateUBOMapping
  • updateBufferData
  • allocateBindingPointIndex
  • gl.createBuffer
  • gl.bindBuffer
  • gl.bufferData
  • gl.bindBufferBase
  • allocatedBindingPoints.indexOf
  • allocatedBindingPoints.push
  • console.error
  • Array.isArray
  • hasUniformChanged
  • getUniformSize
  • gl.bufferSubData
  • value.toArray
  • value.clone
  • cachedObject.equals
  • cachedObject.copy
  • console.warn
  • uniformsGroup.removeEventListener
  • allocatedBindingPoints.splice
  • gl.deleteBuffer

Internal Comments:

// ensure to update the binding points/block indices mapping for this program (x2)
// update UBO once per frame (x2)
// the setup of an UBO is independent of a particular shader program but global (x2)
// TODO add integer and struct support
// manually converting 3x3 to 3x4 (x5)
// cache entry does not exist so far
// compare current value with cached entry
// determine total buffer size according to the STD140 layout (x2)
// Hint: STD140 is the only supported layout in WebGL 2 (x2)
// Check for chunk overflow
// Add padding and adjust offset (x3)
// the following two properties will be used for partial buffer updates (x4)
// Update the global offset (x3)
// ensure correct final padding (x2)
// (x4)
// determine sizes according to STD140
// float/int/bool (x4)
// vec2 (x4)
// vec3 (x4)
// vec4 (x4)
// mat3 (in STD140 a 3x3 matrix is represented as 3x4) (x4)
// mat4 (x4)

Code
function WebGLUniformsGroups( gl, info, capabilities, state ) {

    let buffers = {};
    let updateList = {};
    let allocatedBindingPoints = [];

    const maxBindingPoints = gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ); // binding points are global whereas block indices are per shader program

    function bind( uniformsGroup, program ) {

        const webglProgram = program.program;
        state.uniformBlockBinding( uniformsGroup, webglProgram );

    }

    function update( uniformsGroup, program ) {

        let buffer = buffers[ uniformsGroup.id ];

        if ( buffer === undefined ) {

            prepareUniformsGroup( uniformsGroup );

            buffer = createBuffer( uniformsGroup );
            buffers[ uniformsGroup.id ] = buffer;

            uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );

        }

        // ensure to update the binding points/block indices mapping for this program

        const webglProgram = program.program;
        state.updateUBOMapping( uniformsGroup, webglProgram );

        // update UBO once per frame

        const frame = info.render.frame;

        if ( updateList[ uniformsGroup.id ] !== frame ) {

            updateBufferData( uniformsGroup );

            updateList[ uniformsGroup.id ] = frame;

        }

    }

    function createBuffer( uniformsGroup ) {

        // the setup of an UBO is independent of a particular shader program but global

        const bindingPointIndex = allocateBindingPointIndex();
        uniformsGroup.__bindingPointIndex = bindingPointIndex;

        const buffer = gl.createBuffer();
        const size = uniformsGroup.__size;
        const usage = uniformsGroup.usage;

        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;

    }

    function allocateBindingPointIndex() {

        for ( let i = 0; i < maxBindingPoints; i ++ ) {

            if ( allocatedBindingPoints.indexOf( i ) === -1 ) {

                allocatedBindingPoints.push( i );
                return i;

            }

        }

        console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );

        return 0;

    }

    function updateBufferData( uniformsGroup ) {

        const buffer = buffers[ uniformsGroup.id ];
        const uniforms = uniformsGroup.uniforms;
        const cache = uniformsGroup.__cache;

        gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );

        for ( let i = 0, il = uniforms.length; i < il; i ++ ) {

            const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];

            for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {

                const uniform = uniformArray[ j ];

                if ( hasUniformChanged( uniform, i, j, cache ) === true ) {

                    const offset = uniform.__offset;

                    const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];

                    let arrayOffset = 0;

                    for ( let k = 0; k < values.length; k ++ ) {

                        const value = values[ k ];

                        const info = getUniformSize( value );

                        // 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

                            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( gl.UNIFORM_BUFFER, offset, uniform.__data );

                }

            }

        }

        gl.bindBuffer( gl.UNIFORM_BUFFER, null );

    }

    function hasUniformChanged( uniform, index, indexArray, cache ) {

        const value = uniform.value;
        const indexString = index + '_' + indexArray;

        if ( cache[ indexString ] === undefined ) {

            // cache entry does not exist so far

            if ( typeof value === 'number' || typeof value === 'boolean' ) {

                cache[ indexString ] = value;

            } else {

                cache[ indexString ] = value.clone();

            }

            return true;

        } else {

            const cachedObject = cache[ indexString ];

            // compare current value with cached entry

            if ( typeof value === 'number' || typeof value === 'boolean' ) {

                if ( cachedObject !== value ) {

                    cache[ indexString ] = value;
                    return true;

                }

            } else {

                if ( cachedObject.equals( value ) === false ) {

                    cachedObject.copy( value );
                    return true;

                }

            }

        }

        return false;

    }

    function prepareUniformsGroup( uniformsGroup ) {

        // determine total buffer size according to the STD140 layout
        // Hint: STD140 is the only supported layout in WebGL 2

        const uniforms = uniformsGroup.uniforms;

        let offset = 0; // global buffer offset in bytes
        const chunkSize = 16; // size of a chunk in bytes

        for ( let i = 0, l = uniforms.length; i < l; i ++ ) {

            const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];

            for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {

                const uniform = uniformArray[ j ];

                const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];

                for ( let k = 0, kl = values.length; k < kl; k ++ ) {

                    const value = values[ k ];

                    const info = getUniformSize( value );

                    const chunkOffset = offset % chunkSize; // offset in the current chunk
                    const chunkPadding = chunkOffset % info.boundary; // required padding to match boundary
                    const chunkStart = chunkOffset + chunkPadding; // the start position in the current chunk for the data

                    offset += chunkPadding;

                    // Check for chunk overflow
                    if ( chunkStart !== 0 && ( chunkSize - chunkStart ) < info.storage ) {

                        // Add padding and adjust offset
                        offset += ( chunkSize - chunkStart );

                    }

                    // the following two properties will be used for partial buffer updates
                    uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
                    uniform.__offset = offset;

                    // Update the global offset
                    offset += info.storage;

                }

            }

        }

        // ensure correct final padding

        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

    };

}

bind(uniformsGroup: any, program: any): void

Parameters:

  • uniformsGroup any
  • program any

Returns: void

Calls:

  • state.uniformBlockBinding
Code
function bind( uniformsGroup, program ) {

        const webglProgram = program.program;
        state.uniformBlockBinding( uniformsGroup, webglProgram );

    }

update(uniformsGroup: any, program: any): void

Parameters:

  • uniformsGroup any
  • program any

Returns: void

Calls:

  • prepareUniformsGroup
  • createBuffer
  • uniformsGroup.addEventListener
  • state.updateUBOMapping
  • updateBufferData

Internal Comments:

// ensure to update the binding points/block indices mapping for this program (x2)
// update UBO once per frame (x2)

Code
function update( uniformsGroup, program ) {

        let buffer = buffers[ uniformsGroup.id ];

        if ( buffer === undefined ) {

            prepareUniformsGroup( uniformsGroup );

            buffer = createBuffer( uniformsGroup );
            buffers[ uniformsGroup.id ] = buffer;

            uniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );

        }

        // ensure to update the binding points/block indices mapping for this program

        const webglProgram = program.program;
        state.updateUBOMapping( uniformsGroup, webglProgram );

        // update UBO once per frame

        const frame = info.render.frame;

        if ( updateList[ uniformsGroup.id ] !== frame ) {

            updateBufferData( uniformsGroup );

            updateList[ uniformsGroup.id ] = frame;

        }

    }

createBuffer(uniformsGroup: any): any

Parameters:

  • uniformsGroup any

Returns: any

Calls:

  • allocateBindingPointIndex
  • gl.createBuffer
  • gl.bindBuffer
  • gl.bufferData
  • gl.bindBufferBase

Internal Comments:

// the setup of an UBO is independent of a particular shader program but global (x2)

Code
function createBuffer( uniformsGroup ) {

        // the setup of an UBO is independent of a particular shader program but global

        const bindingPointIndex = allocateBindingPointIndex();
        uniformsGroup.__bindingPointIndex = bindingPointIndex;

        const buffer = gl.createBuffer();
        const size = uniformsGroup.__size;
        const usage = uniformsGroup.usage;

        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;

    }

allocateBindingPointIndex(): number

Returns: number

Calls:

  • allocatedBindingPoints.indexOf
  • allocatedBindingPoints.push
  • console.error
Code
function allocateBindingPointIndex() {

        for ( let i = 0; i < maxBindingPoints; i ++ ) {

            if ( allocatedBindingPoints.indexOf( i ) === -1 ) {

                allocatedBindingPoints.push( i );
                return i;

            }

        }

        console.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );

        return 0;

    }

updateBufferData(uniformsGroup: any): void

Parameters:

  • uniformsGroup any

Returns: void

Calls:

  • gl.bindBuffer
  • Array.isArray
  • hasUniformChanged
  • getUniformSize
  • gl.bufferSubData
  • value.toArray

Internal Comments:

// TODO add integer and struct support
// manually converting 3x3 to 3x4 (x5)

Code
function updateBufferData( uniformsGroup ) {

        const buffer = buffers[ uniformsGroup.id ];
        const uniforms = uniformsGroup.uniforms;
        const cache = uniformsGroup.__cache;

        gl.bindBuffer( gl.UNIFORM_BUFFER, buffer );

        for ( let i = 0, il = uniforms.length; i < il; i ++ ) {

            const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];

            for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {

                const uniform = uniformArray[ j ];

                if ( hasUniformChanged( uniform, i, j, cache ) === true ) {

                    const offset = uniform.__offset;

                    const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];

                    let arrayOffset = 0;

                    for ( let k = 0; k < values.length; k ++ ) {

                        const value = values[ k ];

                        const info = getUniformSize( value );

                        // 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

                            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( gl.UNIFORM_BUFFER, offset, uniform.__data );

                }

            }

        }

        gl.bindBuffer( gl.UNIFORM_BUFFER, null );

    }

hasUniformChanged(uniform: any, index: any, indexArray: any, cache: any): boolean

Parameters:

  • uniform any
  • index any
  • indexArray any
  • cache any

Returns: boolean

Calls:

  • value.clone
  • cachedObject.equals
  • cachedObject.copy

Internal Comments:

// cache entry does not exist so far
// compare current value with cached entry

Code
function hasUniformChanged( uniform, index, indexArray, cache ) {

        const value = uniform.value;
        const indexString = index + '_' + indexArray;

        if ( cache[ indexString ] === undefined ) {

            // cache entry does not exist so far

            if ( typeof value === 'number' || typeof value === 'boolean' ) {

                cache[ indexString ] = value;

            } else {

                cache[ indexString ] = value.clone();

            }

            return true;

        } else {

            const cachedObject = cache[ indexString ];

            // compare current value with cached entry

            if ( typeof value === 'number' || typeof value === 'boolean' ) {

                if ( cachedObject !== value ) {

                    cache[ indexString ] = value;
                    return true;

                }

            } else {

                if ( cachedObject.equals( value ) === false ) {

                    cachedObject.copy( value );
                    return true;

                }

            }

        }

        return false;

    }

prepareUniformsGroup(uniformsGroup: any): any

Parameters:

  • uniformsGroup any

Returns: any

Calls:

  • Array.isArray
  • getUniformSize

Internal Comments:

// determine total buffer size according to the STD140 layout (x2)
// Hint: STD140 is the only supported layout in WebGL 2 (x2)
// Check for chunk overflow
// Add padding and adjust offset (x3)
// the following two properties will be used for partial buffer updates (x4)
// Update the global offset (x3)
// ensure correct final padding (x2)
// (x4)

Code
function prepareUniformsGroup( uniformsGroup ) {

        // determine total buffer size according to the STD140 layout
        // Hint: STD140 is the only supported layout in WebGL 2

        const uniforms = uniformsGroup.uniforms;

        let offset = 0; // global buffer offset in bytes
        const chunkSize = 16; // size of a chunk in bytes

        for ( let i = 0, l = uniforms.length; i < l; i ++ ) {

            const uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];

            for ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {

                const uniform = uniformArray[ j ];

                const values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];

                for ( let k = 0, kl = values.length; k < kl; k ++ ) {

                    const value = values[ k ];

                    const info = getUniformSize( value );

                    const chunkOffset = offset % chunkSize; // offset in the current chunk
                    const chunkPadding = chunkOffset % info.boundary; // required padding to match boundary
                    const chunkStart = chunkOffset + chunkPadding; // the start position in the current chunk for the data

                    offset += chunkPadding;

                    // Check for chunk overflow
                    if ( chunkStart !== 0 && ( chunkSize - chunkStart ) < info.storage ) {

                        // Add padding and adjust offset
                        offset += ( chunkSize - chunkStart );

                    }

                    // the following two properties will be used for partial buffer updates
                    uniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );
                    uniform.__offset = offset;

                    // Update the global offset
                    offset += info.storage;

                }

            }

        }

        // ensure correct final padding

        const chunkOffset = offset % chunkSize;

        if ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );

        //

        uniformsGroup.__size = offset;
        uniformsGroup.__cache = {};

        return this;

    }

getUniformSize(value: any): { boundary: number; storage: number; }

Parameters:

  • value any

Returns: { boundary: number; storage: number; }

Calls:

  • console.warn

Internal Comments:

// determine sizes according to STD140
// float/int/bool (x4)
// vec2 (x4)
// vec3 (x4)
// vec4 (x4)
// mat3 (in STD140 a 3x3 matrix is represented as 3x4) (x4)
// mat4 (x4)

Code
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;

    }

onUniformsGroupsDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • uniformsGroup.removeEventListener
  • allocatedBindingPoints.indexOf
  • allocatedBindingPoints.splice
  • gl.deleteBuffer
Code
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 ];

    }

dispose(): void

Returns: void

Calls:

  • gl.deleteBuffer
Code
function dispose() {

        for ( const id in buffers ) {

            gl.deleteBuffer( buffers[ id ] );

        }

        allocatedBindingPoints = [];
        buffers = {};
        updateList = {};

    }

getTargetPixelRatio(): number

Returns: number

Code
function getTargetPixelRatio() {

            return _currentRenderTarget === null ? _pixelRatio : 1;

        }

getContext(contextName: any, contextAttributes: any): any

Parameters:

  • contextName any
  • contextAttributes any

Returns: any

Calls:

  • canvas.getContext
Code
function getContext( contextName, contextAttributes ) {

            return canvas.getContext( contextName, contextAttributes );

        }

initGLContext(): void

Returns: void

Calls:

  • extensions.init
  • state.buffers.depth.setReversed

Internal Comments:

/**
             * Holds details about the capabilities of the current rendering context.
             *
             * @name WebGLRenderer#capabilities
             * @type {WebGLRenderer~Capabilities}
             */ (x4)
/**
             * Provides methods for retrieving and testing WebGL extensions.
             *
             * - `get(extensionName:string)`: Used to check whether a WebGL extension is supported
             * and return the extension object if available.
             * - `has(extensionName:string)`: returns `true` if the extension is supported.
             *
             * @name WebGLRenderer#extensions
             * @type {Object}
             */ (x4)
/**
             * Used to track properties of other objects like native WebGL objects.
             *
             * @name WebGLRenderer#properties
             * @type {Object}
             */ (x4)
/**
             * Manages the render lists of the renderer.
             *
             * @name WebGLRenderer#renderLists
             * @type {Object}
             */ (x4)
/**
             * Interface for managing shadows.
             *
             * @name WebGLRenderer#shadowMap
             * @type {WebGLRenderer~ShadowMap}
             */ (x4)
/**
             * Interface for managing the WebGL state.
             *
             * @name WebGLRenderer#state
             * @type {Object}
             */ (x4)
/**
             * Holds a series of statistical information about the GPU memory
             * and the rendering process. Useful for debugging and monitoring.
             *
             * By default these data are reset at each render call but when having
             * multiple render passes per frame (e.g. when using post processing) it can
             * be preferred to reset with a custom pattern. First, set `autoReset` to
             * `false`.
             * ```js
             * renderer.info.autoReset = false;
             * ```
             * Call `reset()` whenever you have finished to render a single frame.
             * ```js
             * renderer.info.reset();
             * ```
             *
             * @name WebGLRenderer#info
             * @type {WebGLRenderer~Info}
             */ (x4)

Code
function initGLContext() {

            extensions = new WebGLExtensions( _gl );
            extensions.init();

            utils = new WebGLUtils( _gl, extensions );

            capabilities = new WebGLCapabilities( _gl, extensions, parameters, utils );

            state = new WebGLState( _gl, extensions );

            if ( capabilities.reversedDepthBuffer && reversedDepthBuffer ) {

                state.buffers.depth.setReversed( true );

            }

            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 );
            bindingStates = new WebGLBindingStates( _gl, attributes );
            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 );
            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 );
            indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );

            info.programs = programCache.programs;

            /**
             * Holds details about the capabilities of the current rendering context.
             *
             * @name WebGLRenderer#capabilities
             * @type {WebGLRenderer~Capabilities}
             */
            _this.capabilities = capabilities;

            /**
             * Provides methods for retrieving and testing WebGL extensions.
             *
             * - `get(extensionName:string)`: Used to check whether a WebGL extension is supported
             * and return the extension object if available.
             * - `has(extensionName:string)`: returns `true` if the extension is supported.
             *
             * @name WebGLRenderer#extensions
             * @type {Object}
             */
            _this.extensions = extensions;

            /**
             * Used to track properties of other objects like native WebGL objects.
             *
             * @name WebGLRenderer#properties
             * @type {Object}
             */
            _this.properties = properties;

            /**
             * Manages the render lists of the renderer.
             *
             * @name WebGLRenderer#renderLists
             * @type {Object}
             */
            _this.renderLists = renderLists;



            /**
             * Interface for managing shadows.
             *
             * @name WebGLRenderer#shadowMap
             * @type {WebGLRenderer~ShadowMap}
             */
            _this.shadowMap = shadowMap;

            /**
             * Interface for managing the WebGL state.
             *
             * @name WebGLRenderer#state
             * @type {Object}
             */
            _this.state = state;

            /**
             * Holds a series of statistical information about the GPU memory
             * and the rendering process. Useful for debugging and monitoring.
             *
             * By default these data are reset at each render call but when having
             * multiple render passes per frame (e.g. when using post processing) it can
             * be preferred to reset with a custom pattern. First, set `autoReset` to
             * `false`.
             * ```js
             * renderer.info.autoReset = false;
             * ```
             * Call `reset()` whenever you have finished to render a single frame.
             * ```js
             * renderer.info.reset();
             * ```
             *
             * @name WebGLRenderer#info
             * @type {WebGLRenderer~Info}
             */
            _this.info = info;

        }

onContextLost(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • event.preventDefault
  • console.log
Code
function onContextLost( event ) {

            event.preventDefault();

            console.log( 'THREE.WebGLRenderer: Context Lost.' );

            _isContextLost = true;

        }

onContextRestore(): void

Returns: void

Calls:

  • console.log
  • initGLContext
Code
function onContextRestore( /* event */ ) {

            console.log( 'THREE.WebGLRenderer: Context Restored.' );

            _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;

        }

onContextCreationError(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • console.error
Code
function onContextCreationError( event ) {

            console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );

        }

onMaterialDispose(event: any): void

Parameters:

  • event any

Returns: void

Calls:

  • material.removeEventListener
  • deallocateMaterial
Code
function onMaterialDispose( event ) {

            const material = event.target;

            material.removeEventListener( 'dispose', onMaterialDispose );

            deallocateMaterial( material );

        }

deallocateMaterial(material: any): void

Parameters:

  • material any

Returns: void

Calls:

  • releaseMaterialProgramReferences
  • properties.remove
Code
function deallocateMaterial( material ) {

            releaseMaterialProgramReferences( material );

            properties.remove( material );

        }

releaseMaterialProgramReferences(material: any): void

Parameters:

  • material any

Returns: void

Calls:

  • properties.get
  • programs.forEach
  • programCache.releaseProgram
  • programCache.releaseShaderCache
Code
function releaseMaterialProgramReferences( material ) {

            const programs = properties.get( material ).programs;

            if ( programs !== undefined ) {

                programs.forEach( function ( program ) {

                    programCache.releaseProgram( program );

                } );

                if ( material.isShaderMaterial ) {

                    programCache.releaseShaderCache( material );

                }

            }

        }

prepareMaterial(material: any, scene: any, object: any): void

Parameters:

  • material any
  • scene any
  • object any

Returns: void

Calls:

  • getProgram
Code
function prepareMaterial( material, scene, object ) {

            if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {

                material.side = BackSide;
                material.needsUpdate = true;
                getProgram( material, scene, object );

                material.side = FrontSide;
                material.needsUpdate = true;
                getProgram( material, scene, object );

                material.side = DoubleSide;

            } else {

                getProgram( material, scene, object );

            }

        }

checkMaterialsReady(): void

Returns: void

Calls:

  • materials.forEach
  • properties.get
  • program.isReady
  • materials.delete
  • resolve
  • setTimeout

Internal Comments:

// remove any programs that report they're ready to use from the list (x4)
// once the list of compiling materials is empty, call the callback
// if some materials are still not ready, wait a bit and check again (x3)

Code
function checkMaterialsReady() {

                    materials.forEach( function ( material ) {

                        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 );

                        }

                    } );

                    // once the list of compiling materials is empty, call the callback

                    if ( materials.size === 0 ) {

                        resolve( scene );
                        return;

                    }

                    // if some materials are still not ready, wait a bit and check again

                    setTimeout( checkMaterialsReady, 10 );

                }

onAnimationFrame(time: any): void

Parameters:

  • time any

Returns: void

Calls:

  • onAnimationFrameCallback
Code
function onAnimationFrame( time ) {

            if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );

        }

onXRSessionStart(): void

Returns: void

Calls:

  • animation.stop
Code
function onXRSessionStart() {

            animation.stop();

        }

onXRSessionEnd(): void

Returns: void

Calls:

  • animation.start
Code
function onXRSessionEnd() {

            animation.start();

        }

projectObject(object: any, camera: any, groupOrder: any, sortObjects: any): void

Parameters:

  • object any
  • camera any
  • groupOrder any
  • sortObjects any

Returns: void

Calls:

  • object.layers.test
  • object.update
  • currentRenderState.pushLight
  • currentRenderState.pushShadow
  • _frustum.intersectsSprite
  • _vector4.setFromMatrixPosition( object.matrixWorld ) .applyMatrix4
  • objects.update
  • currentRenderList.push
  • _frustum.intersectsObject
  • object.computeBoundingSphere
  • _vector4.copy
  • geometry.computeBoundingSphere
  • _vector4 .applyMatrix4( object.matrixWorld ) .applyMatrix4
  • Array.isArray
  • projectObject
Code
function projectObject( object, camera, groupOrder, sortObjects ) {

            if ( object.visible === false ) return;

            const visible = object.layers.test( camera.layers );

            if ( visible ) {

                if ( object.isGroup ) {

                    groupOrder = object.renderOrder;

                } else if ( object.isLOD ) {

                    if ( object.autoUpdate === true ) object.update( camera );

                } else if ( object.isLight ) {

                    currentRenderState.pushLight( object );

                    if ( object.castShadow ) {

                        currentRenderState.pushShadow( object );

                    }

                } else if ( object.isSprite ) {

                    if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {

                        if ( sortObjects ) {

                            _vector4.setFromMatrixPosition( object.matrixWorld )
                                .applyMatrix4( _projScreenMatrix );

                        }

                        const geometry = objects.update( object );
                        const material = object.material;

                        if ( material.visible ) {

                            currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );

                        }

                    }

                } else if ( object.isMesh || object.isLine || object.isPoints ) {

                    if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {

                        const geometry = objects.update( object );
                        const material = object.material;

                        if ( sortObjects ) {

                            if ( object.boundingSphere !== undefined ) {

                                if ( object.boundingSphere === null ) object.computeBoundingSphere();
                                _vector4.copy( object.boundingSphere.center );

                            } else {

                                if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
                                _vector4.copy( geometry.boundingSphere.center );

                            }

                            _vector4
                                .applyMatrix4( object.matrixWorld )
                                .applyMatrix4( _projScreenMatrix );

                        }

                        if ( Array.isArray( material ) ) {

                            const groups = geometry.groups;

                            for ( let i = 0, l = groups.length; i < l; i ++ ) {

                                const group = groups[ i ];
                                const groupMaterial = material[ group.materialIndex ];

                                if ( groupMaterial && groupMaterial.visible ) {

                                    currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group );

                                }

                            }

                        } else if ( material.visible ) {

                            currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );

                        }

                    }

                }

            }

            const children = object.children;

            for ( let i = 0, l = children.length; i < l; i ++ ) {

                projectObject( children[ i ], camera, groupOrder, sortObjects );

            }

        }

renderScene(currentRenderList: any, scene: any, camera: any, viewport: any): void

Parameters:

  • currentRenderList any
  • scene any
  • camera any
  • viewport any

Returns: void

Calls:

  • currentRenderState.setupLightsView
  • clipping.setGlobalState
  • state.viewport
  • _currentViewport.copy
  • renderObjects
  • state.buffers.depth.setTest
  • state.buffers.depth.setMask
  • state.buffers.color.setMask
  • state.setPolygonOffset

Internal Comments:

// Ensure depth buffer writing is enabled so it can be cleared on next render (x6)

Code
function renderScene( currentRenderList, scene, camera, viewport ) {

            const opaqueObjects = currentRenderList.opaque;
            const transmissiveObjects = currentRenderList.transmissive;
            const transparentObjects = currentRenderList.transparent;

            currentRenderState.setupLightsView( camera );

            if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );

            if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );

            if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
            if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
            if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );

            // 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 );

            state.setPolygonOffset( false );

        }

renderTransmissionPass(opaqueObjects: any, transmissiveObjects: any, scene: any, camera: any): void

Parameters:

  • opaqueObjects any
  • transmissiveObjects any
  • scene any
  • camera any

Returns: void

Calls:

  • extensions.has
  • transmissionRenderTarget.setSize
  • _this.getRenderTarget
  • _this.getActiveCubeFace
  • _this.getActiveMipmapLevel
  • _this.setRenderTarget
  • _this.getClearColor
  • _this.getClearAlpha
  • _this.setClearColor
  • _this.clear
  • background.render
  • currentRenderState.setupLightsView
  • clipping.setGlobalState
  • renderObjects
  • textures.updateMultisampleRenderTarget
  • textures.updateRenderTargetMipmap
  • object.layers.test
  • renderObject

Internal Comments:

// (x2)
// Turn off the features which can affect the frag color for opaque objects pass. (x2)
// Otherwise they are applied twice in opaque objects pass and transmission objects pass. (x2)
// Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector). (x2)
// Transmission render pass requires viewport to match the transmissionRenderTarget. (x2)

Code
function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {

            const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;

            if ( overrideMaterial !== null ) {

                return;

            }

            if ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) {

                currentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, {
                    generateMipmaps: true,
                    type: ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ) ? HalfFloatType : UnsignedByteType,
                    minFilter: LinearMipmapLinearFilter,
                    samples: 4,
                    stencilBuffer: stencil,
                    resolveDepthBuffer: false,
                    resolveStencilBuffer: false,
                    colorSpace: ColorManagement.workingColorSpace,
                } );

                // debug

                /*
                const geometry = new PlaneGeometry();
                const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );

                const mesh = new Mesh( geometry, material );
                scene.add( mesh );
                */

            }

            const transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ];

            const activeViewport = camera.viewport || _currentViewport;
            transmissionRenderTarget.setSize( activeViewport.z * _this.transmissionResolutionScale, activeViewport.w * _this.transmissionResolutionScale );

            //

            const currentRenderTarget = _this.getRenderTarget();
            const currentActiveCubeFace = _this.getActiveCubeFace();
            const currentActiveMipmapLevel = _this.getActiveMipmapLevel();

            _this.setRenderTarget( transmissionRenderTarget );

            _this.getClearColor( _currentClearColor );
            _currentClearAlpha = _this.getClearAlpha();
            if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );

            _this.clear();

            if ( _renderBackground ) background.render( scene );

            // 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;

            // Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector).
            // Transmission render pass requires viewport to match the transmissionRenderTarget.
            const currentCameraViewport = camera.viewport;
            if ( camera.viewport !== undefined ) camera.viewport = undefined;

            currentRenderState.setupLightsView( camera );

            if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );

            renderObjects( opaqueObjects, scene, camera );

            textures.updateMultisampleRenderTarget( transmissionRenderTarget );
            textures.updateRenderTargetMipmap( transmissionRenderTarget );

            if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131

                let renderTargetNeedsUpdate = false;

                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;

                    if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {

                        const currentSide = material.side;

                        material.side = BackSide;
                        material.needsUpdate = true;

                        renderObject( object, scene, camera, geometry, material, group );

                        material.side = currentSide;
                        material.needsUpdate = true;

                        renderTargetNeedsUpdate = true;

                    }

                }

                if ( renderTargetNeedsUpdate === true ) {

                    textures.updateMultisampleRenderTarget( transmissionRenderTarget );
                    textures.updateRenderTargetMipmap( transmissionRenderTarget );

                }

            }

            _this.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );

            _this.setClearColor( _currentClearColor, _currentClearAlpha );

            if ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport;

            _this.toneMapping = currentToneMapping;

        }

renderObjects(renderList: any, scene: any, camera: any): void

Parameters:

  • renderList any
  • scene any
  • camera any

Returns: void

Calls:

  • object.layers.test
  • renderObject
Code
function renderObjects( renderList, scene, camera ) {

            const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;

            for ( let i = 0, l = renderList.length; i < l; i ++ ) {

                const renderItem = renderList[ i ];

                const object = renderItem.object;
                const geometry = renderItem.geometry;
                const group = renderItem.group;
                let material = renderItem.material;

                if ( material.allowOverride === true && overrideMaterial !== null ) {

                    material = overrideMaterial;

                }

                if ( object.layers.test( camera.layers ) ) {

                    renderObject( object, scene, camera, geometry, material, group );

                }

            }

        }

renderObject(object: any, scene: any, camera: any, geometry: any, material: any, group: any): void

Parameters:

  • object any
  • scene any
  • camera any
  • geometry any
  • material any
  • group any

Returns: void

Calls:

  • object.onBeforeRender
  • object.modelViewMatrix.multiplyMatrices
  • object.normalMatrix.getNormalMatrix
  • material.onBeforeRender
  • _this.renderBufferDirect
  • object.onAfterRender
Code
function renderObject( object, scene, camera, geometry, material, group ) {

            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 );

            if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {

                material.side = BackSide;
                material.needsUpdate = true;
                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

                material.side = FrontSide;
                material.needsUpdate = true;
                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

                material.side = DoubleSide;

            } else {

                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

            }

            object.onAfterRender( _this, scene, camera, geometry, material, group );

        }

getProgram(material: any, scene: any, object: any): any

Parameters:

  • material any
  • scene any
  • object any

Returns: any

Calls:

  • properties.get
  • programCache.getParameters
  • programCache.getProgramCacheKey
  • ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get
  • material.addEventListener
  • programs.get
  • updateCommonMaterialProperties
  • programCache.getUniforms
  • material.onBeforeCompile
  • programCache.acquireProgram
  • programs.set
  • materialNeedsLights

Internal Comments:

// always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change (x4)
// new material (x4)
// early out if program and light state is identical
// store the light setup it was created for (x4)
// wire up the material to this renderer's lighting state (x5)

Code
function getProgram( material, scene, object ) {

            if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...

            const materialProperties = properties.get( material );

            const lights = currentRenderState.state.lights;
            const shadowsArray = currentRenderState.state.shadowsArray;

            const lightsStateVersion = lights.state.version;

            const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
            const programCacheKey = programCache.getProgramCacheKey( parameters );

            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

            materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
            materialProperties.fog = scene.fog;
            materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
            materialProperties.envMapRotation = ( materialProperties.environment !== null && material.envMap === null ) ? scene.environmentRotation : material.envMapRotation;

            if ( programs === undefined ) {

                // new material

                material.addEventListener( 'dispose', onMaterialDispose );

                programs = new Map();
                materialProperties.programs = programs;

            }

            let program = programs.get( programCacheKey );

            if ( program !== undefined ) {

                // early out if program and light state is identical

                if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {

                    updateCommonMaterialProperties( material, parameters );

                    return program;

                }

            } else {

                parameters.uniforms = programCache.getUniforms( material );

                material.onBeforeCompile( parameters, _this );

                program = programCache.acquireProgram( parameters, programCacheKey );
                programs.set( programCacheKey, program );

                materialProperties.uniforms = parameters.uniforms;

            }

            const uniforms = materialProperties.uniforms;

            if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {

                uniforms.clippingPlanes = clipping.uniform;

            }

            updateCommonMaterialProperties( material, parameters );

            // store the light setup it was created for

            materialProperties.needsLights = materialNeedsLights( material );
            materialProperties.lightsStateVersion = lightsStateVersion;

            if ( materialProperties.needsLights ) {

                // wire up the material to this renderer's lighting state

                uniforms.ambientLightColor.value = lights.state.ambient;
                uniforms.lightProbe.value = lights.state.probe;
                uniforms.directionalLights.value = lights.state.directional;
                uniforms.directionalLightShadows.value = lights.state.directionalShadow;
                uniforms.spotLights.value = lights.state.spot;
                uniforms.spotLightShadows.value = lights.state.spotShadow;
                uniforms.rectAreaLights.value = lights.state.rectArea;
                uniforms.ltc_1.value = lights.state.rectAreaLTC1;
                uniforms.ltc_2.value = lights.state.rectAreaLTC2;
                uniforms.pointLights.value = lights.state.point;
                uniforms.pointLightShadows.value = lights.state.pointShadow;
                uniforms.hemisphereLights.value = lights.state.hemi;

                uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
                uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
                uniforms.spotShadowMap.value = lights.state.spotShadowMap;
                uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
                uniforms.spotLightMap.value = lights.state.spotLightMap;
                uniforms.pointShadowMap.value = lights.state.pointShadowMap;
                uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
                // TODO (abelnation): add area lights shadow info to uniforms

            }

            materialProperties.currentProgram = program;
            materialProperties.uniformsList = null;

            return program;

        }

getUniformList(materialProperties: any): any

Parameters:

  • materialProperties any

Returns: any

Calls:

  • materialProperties.currentProgram.getUniforms
  • WebGLUniforms.seqWithValue
Code
function getUniformList( materialProperties ) {

            if ( materialProperties.uniformsList === null ) {

                const progUniforms = materialProperties.currentProgram.getUniforms();
                materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );

            }

            return materialProperties.uniformsList;

        }

updateCommonMaterialProperties(material: any, parameters: any): void

Parameters:

  • material any
  • parameters any

Returns: void

Calls:

  • properties.get
Code
function updateCommonMaterialProperties( material, parameters ) {

            const materialProperties = properties.get( material );

            materialProperties.outputColorSpace = parameters.outputColorSpace;
            materialProperties.batching = parameters.batching;
            materialProperties.batchingColor = parameters.batchingColor;
            materialProperties.instancing = parameters.instancing;
            materialProperties.instancingColor = parameters.instancingColor;
            materialProperties.instancingMorph = parameters.instancingMorph;
            materialProperties.skinning = parameters.skinning;
            materialProperties.morphTargets = parameters.morphTargets;
            materialProperties.morphNormals = parameters.morphNormals;
            materialProperties.morphColors = parameters.morphColors;
            materialProperties.morphTargetsCount = parameters.morphTargetsCount;
            materialProperties.numClippingPlanes = parameters.numClippingPlanes;
            materialProperties.numIntersection = parameters.numClipIntersection;
            materialProperties.vertexAlphas = parameters.vertexAlphas;
            materialProperties.vertexTangents = parameters.vertexTangents;
            materialProperties.toneMapping = parameters.toneMapping;

        }

setProgram(camera: any, scene: any, geometry: any, material: any, object: any): any

Parameters:

  • camera any
  • scene any
  • geometry any
  • material any
  • object any

Returns: any

Calls:

  • textures.resetTextureUnits
  • ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get
  • properties.get
  • clipping.setState
  • getProgram
  • program.getUniforms
  • state.useProgram
  • state.buffers.depth.getReversed
  • camera.updateProjectionMatrix
  • p_uniforms.setValue
  • uCamPos.setValue
  • _vector3.setFromMatrixPosition
  • Math.log
  • p_uniforms.setOptional
  • skeleton.computeBoneTexture
  • morphtargets.update
  • markUniformsLightsNeedsUpdate
  • materials.refreshFogUniforms
  • materials.refreshMaterialUniforms
  • WebGLUniforms.upload
  • getUniformList
  • uniformsGroups.update
  • uniformsGroups.bind

Internal Comments:

// we might want to call this function with some ClippingGroup (x4)
// object instead of the material, once it becomes feasible (x4)
// (#8465, #8379) (x4)
// (x7)
// common camera uniforms (x2)
// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067
// lighting uniforms depend on the camera so enforce an update (x3)
// now, in case this material supports lights - or later, when (x3)
// the next material that does gets activated: (x3)
// 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
// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512
// the current material requires lighting info (x3)
// note: all lighting uniforms are always set correctly (x3)
// they simply reference the renderer's state for their (x3)
// values (x3)
// use the current material's .needsUpdate flags to set (x3)
// the GL state when required (x3)
// refresh uniforms common to several materials
// common matrices (x4)
// UBOs

Code
function setProgram( camera, scene, geometry, material, object ) {

            if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...

            textures.resetTextureUnits();

            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;

            let toneMapping = NoToneMapping;

            if ( material.toneMapped ) {

                if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {

                    toneMapping = _this.toneMapping;

                }

            }

            const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
            const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

            const materialProperties = properties.get( material );
            const lights = currentRenderState.state.lights;

            if ( _clippingEnabled === true ) {

                if ( _localClippingEnabled === true || camera !== _currentCamera ) {

                    const useCache =
                        camera === _currentCamera &&
                        material.id === _currentMaterialId;

                    // 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 );

                }

            }

            //

            let needsProgramChange = false;

            if ( material.version === materialProperties.__version ) {

                if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {

                    needsProgramChange = true;

                } else if ( materialProperties.outputColorSpace !== colorSpace ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batching === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batchingColor === true && object.colorTexture === null ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batchingColor === false && object.colorTexture !== null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {

                    needsProgramChange = true;

                } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null ) {

                    needsProgramChange = true;

                } else if ( materialProperties.envMap !== envMap ) {

                    needsProgramChange = true;

                } else if ( material.fog === true && materialProperties.fog !== fog ) {

                    needsProgramChange = true;

                } else if ( materialProperties.numClippingPlanes !== undefined &&
                    ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
                    materialProperties.numIntersection !== clipping.numIntersection ) ) {

                    needsProgramChange = true;

                } else if ( materialProperties.vertexAlphas !== vertexAlphas ) {

                    needsProgramChange = true;

                } else if ( materialProperties.vertexTangents !== vertexTangents ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphTargets !== morphTargets ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphNormals !== morphNormals ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphColors !== morphColors ) {

                    needsProgramChange = true;

                } else if ( materialProperties.toneMapping !== toneMapping ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphTargetsCount !== morphTargetsCount ) {

                    needsProgramChange = true;

                }

            } else {

                needsProgramChange = true;
                materialProperties.__version = material.version;

            }

            //

            let program = materialProperties.currentProgram;

            if ( needsProgramChange === true ) {

                program = getProgram( material, scene, object );

            }

            let refreshProgram = false;
            let refreshMaterial = false;
            let refreshLights = false;

            const p_uniforms = program.getUniforms(),
                m_uniforms = materialProperties.uniforms;

            if ( state.useProgram( program.program ) ) {

                refreshProgram = true;
                refreshMaterial = true;
                refreshLights = true;

            }

            if ( material.id !== _currentMaterialId ) {

                _currentMaterialId = material.id;

                refreshMaterial = true;

            }

            if ( refreshProgram || _currentCamera !== camera ) {

                // common camera uniforms

                const reversedDepthBuffer = state.buffers.depth.getReversed();

                if ( reversedDepthBuffer && camera.reversedDepth !== true ) {

                    camera._reversedDepth = true;
                    camera.updateProjectionMatrix();

                }

                p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );

                p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );

                const uCamPos = p_uniforms.map.cameraPosition;

                if ( uCamPos !== undefined ) {

                    uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );

                }

                if ( capabilities.logarithmicDepthBuffer ) {

                    p_uniforms.setValue( _gl, 'logDepthBufFC',
                        2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );

                }

                // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067

                if ( material.isMeshPhongMaterial ||
                    material.isMeshToonMaterial ||
                    material.isMeshLambertMaterial ||
                    material.isMeshBasicMaterial ||
                    material.isMeshStandardMaterial ||
                    material.isShaderMaterial ) {

                    p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );

                }

                if ( _currentCamera !== camera ) {

                    _currentCamera = camera;

                    // 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

                }

            }

            // 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 ) {

                p_uniforms.setOptional( _gl, object, 'bindMatrix' );
                p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );

                const skeleton = object.skeleton;

                if ( skeleton ) {

                    if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();

                    p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );

                }

            }

            if ( object.isBatchedMesh ) {

                p_uniforms.setOptional( _gl, object, 'batchingTexture' );
                p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );

                p_uniforms.setOptional( _gl, object, 'batchingIdTexture' );
                p_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures );

                p_uniforms.setOptional( _gl, object, 'batchingColorTexture' );
                if ( object._colorsTexture !== null ) {

                    p_uniforms.setValue( _gl, 'batchingColorTexture', object._colorsTexture, textures );

                }

            }

            const morphAttributes = geometry.morphAttributes;

            if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined ) ) {

                morphtargets.update( object, geometry, program );

            }

            if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {

                materialProperties.receiveShadow = object.receiveShadow;
                p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );

            }

            // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512

            if ( material.isMeshGouraudMaterial && material.envMap !== null ) {

                m_uniforms.envMap.value = envMap;

                m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? -1 : 1;

            }

            if ( material.isMeshStandardMaterial && material.envMap === null && scene.environment !== null ) {

                m_uniforms.envMapIntensity.value = scene.environmentIntensity;

            }

            if ( refreshMaterial ) {

                p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );

                if ( materialProperties.needsLights ) {

                    // the current material requires lighting info

                    // 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

                if ( fog && material.fog === true ) {

                    materials.refreshFogUniforms( m_uniforms, fog );

                }

                materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] );

                WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );

            }

            if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {

                WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
                material.uniformsNeedUpdate = false;

            }

            if ( material.isSpriteMaterial ) {

                p_uniforms.setValue( _gl, 'center', object.center );

            }

            // common matrices

            p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
            p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
            p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );

            // UBOs

            if ( material.isShaderMaterial || material.isRawShaderMaterial ) {

                const groups = material.uniformsGroups;

                for ( let i = 0, l = groups.length; i < l; i ++ ) {

                    const group = groups[ i ];

                    uniformsGroups.update( group, program );
                    uniformsGroups.bind( group, program );

                }

            }

            return program;

        }

markUniformsLightsNeedsUpdate(uniforms: any, value: any): void

Parameters:

  • uniforms any
  • value any

Returns: void

Code
function markUniformsLightsNeedsUpdate( uniforms, value ) {

            uniforms.ambientLightColor.needsUpdate = value;
            uniforms.lightProbe.needsUpdate = value;

            uniforms.directionalLights.needsUpdate = value;
            uniforms.directionalLightShadows.needsUpdate = value;
            uniforms.pointLights.needsUpdate = value;
            uniforms.pointLightShadows.needsUpdate = value;
            uniforms.spotLights.needsUpdate = value;
            uniforms.spotLightShadows.needsUpdate = value;
            uniforms.rectAreaLights.needsUpdate = value;
            uniforms.hemisphereLights.needsUpdate = value;

        }

materialNeedsLights(material: any): any

Parameters:

  • material any

Returns: any

Code
function materialNeedsLights( material ) {

            return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
                material.isMeshStandardMaterial || material.isShadowMaterial ||
                ( material.isShaderMaterial && material.lights === true );

        }

Classes

PMREMGenerator

Class Code
class PMREMGenerator {

    /**
     * Constructs a new PMREM generator.
     *
     * @param {WebGLRenderer} renderer - The renderer.
     */
    constructor( renderer ) {

        this._renderer = renderer;
        this._pingPongRenderTarget = null;

        this._lodMax = 0;
        this._cubeSize = 0;
        this._lodPlanes = [];
        this._sizeLods = [];
        this._sigmas = [];

        this._blurMaterial = null;
        this._cubemapMaterial = null;
        this._equirectMaterial = null;

        this._compileMaterial( this._blurMaterial );

    }

    /**
     * Generates a PMREM from a supplied Scene, which can be faster than using an
     * image if networking bandwidth is low. Optional sigma specifies a blur radius
     * in radians to be applied to the scene before PMREM generation. Optional near
     * and far planes ensure the scene is rendered in its entirety.
     *
     * @param {Scene} scene - The scene to be captured.
     * @param {number} [sigma=0] - The blur radius in radians.
     * @param {number} [near=0.1] - The near plane distance.
     * @param {number} [far=100] - The far plane distance.
     * @param {Object} [options={}] - The configuration options.
     * @param {number} [options.size=256] - The texture size of the PMREM.
     * @param {Vector3} [options.renderTarget=origin] - The position of the internal cube camera that renders the scene.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */
    fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) {

        const {
            size = 256,
            position = _origin,
        } = options;

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        this._setSize( size );

        const cubeUVRenderTarget = this._allocateTargets();
        cubeUVRenderTarget.depthBuffer = true;

        this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position );

        if ( sigma > 0 ) {

            this._blur( cubeUVRenderTarget, 0, 0, sigma );

        }

        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }

    /**
     * Generates a PMREM from an equirectangular texture, which can be either LDR
     * or HDR. The ideal input image size is 1k (1024 x 512),
     * as this matches best with the 256 x 256 cubemap output.
     *
     * @param {Texture} equirectangular - The equirectangular texture to be converted.
     * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */
    fromEquirectangular( equirectangular, renderTarget = null ) {

        return this._fromTexture( equirectangular, renderTarget );

    }

    /**
     * Generates a PMREM from an cubemap texture, which can be either LDR
     * or HDR. The ideal input cube size is 256 x 256,
     * as this matches best with the 256 x 256 cubemap output.
     *
     * @param {Texture} cubemap - The cubemap texture to be converted.
     * @param {?WebGLRenderTarget} [renderTarget=null] - The render target to use.
     * @return {WebGLRenderTarget} The resulting PMREM.
     */
    fromCubemap( cubemap, renderTarget = null ) {

        return this._fromTexture( cubemap, renderTarget );

    }

    /**
     * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
     * your texture's network fetch for increased concurrency.
     */
    compileCubemapShader() {

        if ( this._cubemapMaterial === null ) {

            this._cubemapMaterial = _getCubemapMaterial();
            this._compileMaterial( this._cubemapMaterial );

        }

    }

    /**
     * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
     * your texture's network fetch for increased concurrency.
     */
    compileEquirectangularShader() {

        if ( this._equirectMaterial === null ) {

            this._equirectMaterial = _getEquirectMaterial();
            this._compileMaterial( this._equirectMaterial );

        }

    }

    /**
     * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
     * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
     * one of them will cause any others to also become unusable.
     */
    dispose() {

        this._dispose();

        if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
        if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();

    }

    // private interface

    _setSize( cubeSize ) {

        this._lodMax = Math.floor( Math.log2( cubeSize ) );
        this._cubeSize = Math.pow( 2, this._lodMax );

    }

    _dispose() {

        if ( this._blurMaterial !== null ) this._blurMaterial.dispose();

        if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();

        for ( let i = 0; i < this._lodPlanes.length; i ++ ) {

            this._lodPlanes[ i ].dispose();

        }

    }

    _cleanup( outputTarget ) {

        this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
        this._renderer.xr.enabled = _oldXrEnabled;

        outputTarget.scissorTest = false;
        _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );

    }

    _fromTexture( texture, renderTarget ) {

        if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {

            this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );

        } else { // Equirectangular

            this._setSize( texture.image.width / 4 );

        }

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        const cubeUVRenderTarget = renderTarget || this._allocateTargets();
        this._textureToCubeUV( texture, cubeUVRenderTarget );
        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }

    _allocateTargets() {

        const width = 3 * Math.max( this._cubeSize, 16 * 7 );
        const height = 4 * this._cubeSize;

        const params = {
            magFilter: LinearFilter,
            minFilter: LinearFilter,
            generateMipmaps: false,
            type: HalfFloatType,
            format: RGBAFormat,
            colorSpace: LinearSRGBColorSpace,
            depthBuffer: false
        };

        const cubeUVRenderTarget = _createRenderTarget( width, height, params );

        if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {

            if ( this._pingPongRenderTarget !== null ) {

                this._dispose();

            }

            this._pingPongRenderTarget = _createRenderTarget( width, height, params );

            const { _lodMax } = this;
            ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );

            this._blurMaterial = _getBlurShader( _lodMax, width, height );

        }

        return cubeUVRenderTarget;

    }

    _compileMaterial( material ) {

        const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
        this._renderer.compile( tmpMesh, _flatCamera );

    }

    _sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ) {

        const fov = 90;
        const aspect = 1;
        const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
        const upSign = [ 1, -1, 1, 1, 1, 1 ];
        const forwardSign = [ 1, 1, 1, -1, -1, -1 ];
        const renderer = this._renderer;

        const originalAutoClear = renderer.autoClear;
        const toneMapping = renderer.toneMapping;
        renderer.getClearColor( _clearColor );

        renderer.toneMapping = NoToneMapping;
        renderer.autoClear = false;

        // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812
        const reversedDepthBuffer = renderer.state.buffers.depth.getReversed();

        if ( reversedDepthBuffer ) {

            renderer.setRenderTarget( cubeUVRenderTarget );
            renderer.clearDepth();
            renderer.setRenderTarget( null );

        }

        const backgroundMaterial = new MeshBasicMaterial( {
            name: 'PMREM.Background',
            side: BackSide,
            depthWrite: false,
            depthTest: false,
        } );

        const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );

        let useSolidColor = false;
        const background = scene.background;

        if ( background ) {

            if ( background.isColor ) {

                backgroundMaterial.color.copy( background );
                scene.background = null;
                useSolidColor = true;

            }

        } else {

            backgroundMaterial.color.copy( _clearColor );
            useSolidColor = true;

        }

        for ( let i = 0; i < 6; i ++ ) {

            const col = i % 3;

            if ( col === 0 ) {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x + forwardSign[ i ], position.y, position.z );

            } else if ( col === 1 ) {

                cubeCamera.up.set( 0, 0, upSign[ i ] );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y + forwardSign[ i ], position.z );


            } else {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y, position.z + forwardSign[ i ] );

            }

            const size = this._cubeSize;

            _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );

            renderer.setRenderTarget( cubeUVRenderTarget );

            if ( useSolidColor ) {

                renderer.render( backgroundBox, cubeCamera );

            }

            renderer.render( scene, cubeCamera );

        }

        backgroundBox.geometry.dispose();
        backgroundBox.material.dispose();

        renderer.toneMapping = toneMapping;
        renderer.autoClear = originalAutoClear;
        scene.background = background;

    }

    _textureToCubeUV( texture, cubeUVRenderTarget ) {

        const renderer = this._renderer;

        const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );

        if ( isCubeTexture ) {

            if ( this._cubemapMaterial === null ) {

                this._cubemapMaterial = _getCubemapMaterial();

            }

            this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? -1 : 1;

        } else {

            if ( this._equirectMaterial === null ) {

                this._equirectMaterial = _getEquirectMaterial();

            }

        }

        const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
        const mesh = new Mesh( this._lodPlanes[ 0 ], material );

        const uniforms = material.uniforms;

        uniforms[ 'envMap' ].value = texture;

        const size = this._cubeSize;

        _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );

        renderer.setRenderTarget( cubeUVRenderTarget );
        renderer.render( mesh, _flatCamera );

    }

    _applyPMREM( cubeUVRenderTarget ) {

        const renderer = this._renderer;
        const autoClear = renderer.autoClear;
        renderer.autoClear = false;
        const n = this._lodPlanes.length;

        for ( let i = 1; i < n; i ++ ) {

            const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );

            const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];

            this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );

        }

        renderer.autoClear = autoClear;

    }

    /**
     * This is a two-pass Gaussian blur for a cubemap. Normally this is done
     * vertically and horizontally, but this breaks down on a cube. Here we apply
     * the blur latitudinally (around the poles), and then longitudinally (towards
     * the poles) to approximate the orthogonally-separable blur. It is least
     * accurate at the poles, but still does a decent job.
     *
     * @private
     * @param {WebGLRenderTarget} cubeUVRenderTarget
     * @param {number} lodIn
     * @param {number} lodOut
     * @param {number} sigma
     * @param {Vector3} [poleAxis]
     */
    _blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {

        const pingPongRenderTarget = this._pingPongRenderTarget;

        this._halfBlur(
            cubeUVRenderTarget,
            pingPongRenderTarget,
            lodIn,
            lodOut,
            sigma,
            'latitudinal',
            poleAxis );

        this._halfBlur(
            pingPongRenderTarget,
            cubeUVRenderTarget,
            lodOut,
            lodOut,
            sigma,
            'longitudinal',
            poleAxis );

    }

    _halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {

        const renderer = this._renderer;
        const blurMaterial = this._blurMaterial;

        if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {

            console.error(
                'blur direction must be either latitudinal or longitudinal!' );

        }

        // Number of standard deviations at which to cut off the discrete approximation.
        const STANDARD_DEVIATIONS = 3;

        const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
        const blurUniforms = blurMaterial.uniforms;

        const pixels = this._sizeLods[ lodIn ] - 1;
        const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
        const sigmaPixels = sigmaRadians / radiansPerPixel;
        const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;

        if ( samples > MAX_SAMPLES ) {

            console.warn( `sigmaRadians, ${
                sigmaRadians}, is too large and will clip, as it requested ${
                samples} samples when the maximum is set to ${MAX_SAMPLES}` );

        }

        const weights = [];
        let sum = 0;

        for ( let i = 0; i < MAX_SAMPLES; ++ i ) {

            const x = i / sigmaPixels;
            const weight = Math.exp( - x * x / 2 );
            weights.push( weight );

            if ( i === 0 ) {

                sum += weight;

            } else if ( i < samples ) {

                sum += 2 * weight;

            }

        }

        for ( let i = 0; i < weights.length; i ++ ) {

            weights[ i ] = weights[ i ] / sum;

        }

        blurUniforms[ 'envMap' ].value = targetIn.texture;
        blurUniforms[ 'samples' ].value = samples;
        blurUniforms[ 'weights' ].value = weights;
        blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';

        if ( poleAxis ) {

            blurUniforms[ 'poleAxis' ].value = poleAxis;

        }

        const { _lodMax } = this;
        blurUniforms[ 'dTheta' ].value = radiansPerPixel;
        blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;

        const outputSize = this._sizeLods[ lodOut ];
        const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
        const y = 4 * ( this._cubeSize - outputSize );

        _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
        renderer.setRenderTarget( targetOut );
        renderer.render( blurMesh, _flatCamera );

    }

}

Methods

fromScene(scene: Scene, sigma: number, near: number, far: number, options: { size?: number; renderTarget?: Vector3; }): WebGLRenderTarget
Code
fromScene( scene, sigma = 0, near = 0.1, far = 100, options = {} ) {

        const {
            size = 256,
            position = _origin,
        } = options;

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        this._setSize( size );

        const cubeUVRenderTarget = this._allocateTargets();
        cubeUVRenderTarget.depthBuffer = true;

        this._sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position );

        if ( sigma > 0 ) {

            this._blur( cubeUVRenderTarget, 0, 0, sigma );

        }

        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }
fromEquirectangular(equirectangular: Texture, renderTarget: WebGLRenderTarget): WebGLRenderTarget
Code
fromEquirectangular( equirectangular, renderTarget = null ) {

        return this._fromTexture( equirectangular, renderTarget );

    }
fromCubemap(cubemap: Texture, renderTarget: WebGLRenderTarget): WebGLRenderTarget
Code
fromCubemap( cubemap, renderTarget = null ) {

        return this._fromTexture( cubemap, renderTarget );

    }
compileCubemapShader(): void
Code
compileCubemapShader() {

        if ( this._cubemapMaterial === null ) {

            this._cubemapMaterial = _getCubemapMaterial();
            this._compileMaterial( this._cubemapMaterial );

        }

    }
compileEquirectangularShader(): void
Code
compileEquirectangularShader() {

        if ( this._equirectMaterial === null ) {

            this._equirectMaterial = _getEquirectMaterial();
            this._compileMaterial( this._equirectMaterial );

        }

    }
dispose(): void
Code
dispose() {

        this._dispose();

        if ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();
        if ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();

    }
_setSize(cubeSize: any): void
Code
_setSize( cubeSize ) {

        this._lodMax = Math.floor( Math.log2( cubeSize ) );
        this._cubeSize = Math.pow( 2, this._lodMax );

    }
_dispose(): void
Code
_dispose() {

        if ( this._blurMaterial !== null ) this._blurMaterial.dispose();

        if ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();

        for ( let i = 0; i < this._lodPlanes.length; i ++ ) {

            this._lodPlanes[ i ].dispose();

        }

    }
_cleanup(outputTarget: any): void
Code
_cleanup( outputTarget ) {

        this._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );
        this._renderer.xr.enabled = _oldXrEnabled;

        outputTarget.scissorTest = false;
        _setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );

    }
_fromTexture(texture: any, renderTarget: any): any
Code
_fromTexture( texture, renderTarget ) {

        if ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {

            this._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );

        } else { // Equirectangular

            this._setSize( texture.image.width / 4 );

        }

        _oldTarget = this._renderer.getRenderTarget();
        _oldActiveCubeFace = this._renderer.getActiveCubeFace();
        _oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();
        _oldXrEnabled = this._renderer.xr.enabled;

        this._renderer.xr.enabled = false;

        const cubeUVRenderTarget = renderTarget || this._allocateTargets();
        this._textureToCubeUV( texture, cubeUVRenderTarget );
        this._applyPMREM( cubeUVRenderTarget );
        this._cleanup( cubeUVRenderTarget );

        return cubeUVRenderTarget;

    }
_allocateTargets(): WebGLRenderTarget
Code
_allocateTargets() {

        const width = 3 * Math.max( this._cubeSize, 16 * 7 );
        const height = 4 * this._cubeSize;

        const params = {
            magFilter: LinearFilter,
            minFilter: LinearFilter,
            generateMipmaps: false,
            type: HalfFloatType,
            format: RGBAFormat,
            colorSpace: LinearSRGBColorSpace,
            depthBuffer: false
        };

        const cubeUVRenderTarget = _createRenderTarget( width, height, params );

        if ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {

            if ( this._pingPongRenderTarget !== null ) {

                this._dispose();

            }

            this._pingPongRenderTarget = _createRenderTarget( width, height, params );

            const { _lodMax } = this;
            ( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );

            this._blurMaterial = _getBlurShader( _lodMax, width, height );

        }

        return cubeUVRenderTarget;

    }
_compileMaterial(material: any): void
Code
_compileMaterial( material ) {

        const tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );
        this._renderer.compile( tmpMesh, _flatCamera );

    }
_sceneToCubeUV(scene: any, near: any, far: any, cubeUVRenderTarget: any, position: any): void
Code
_sceneToCubeUV( scene, near, far, cubeUVRenderTarget, position ) {

        const fov = 90;
        const aspect = 1;
        const cubeCamera = new PerspectiveCamera( fov, aspect, near, far );
        const upSign = [ 1, -1, 1, 1, 1, 1 ];
        const forwardSign = [ 1, 1, 1, -1, -1, -1 ];
        const renderer = this._renderer;

        const originalAutoClear = renderer.autoClear;
        const toneMapping = renderer.toneMapping;
        renderer.getClearColor( _clearColor );

        renderer.toneMapping = NoToneMapping;
        renderer.autoClear = false;

        // https://github.com/mrdoob/three.js/issues/31413#issuecomment-3095966812
        const reversedDepthBuffer = renderer.state.buffers.depth.getReversed();

        if ( reversedDepthBuffer ) {

            renderer.setRenderTarget( cubeUVRenderTarget );
            renderer.clearDepth();
            renderer.setRenderTarget( null );

        }

        const backgroundMaterial = new MeshBasicMaterial( {
            name: 'PMREM.Background',
            side: BackSide,
            depthWrite: false,
            depthTest: false,
        } );

        const backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );

        let useSolidColor = false;
        const background = scene.background;

        if ( background ) {

            if ( background.isColor ) {

                backgroundMaterial.color.copy( background );
                scene.background = null;
                useSolidColor = true;

            }

        } else {

            backgroundMaterial.color.copy( _clearColor );
            useSolidColor = true;

        }

        for ( let i = 0; i < 6; i ++ ) {

            const col = i % 3;

            if ( col === 0 ) {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x + forwardSign[ i ], position.y, position.z );

            } else if ( col === 1 ) {

                cubeCamera.up.set( 0, 0, upSign[ i ] );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y + forwardSign[ i ], position.z );


            } else {

                cubeCamera.up.set( 0, upSign[ i ], 0 );
                cubeCamera.position.set( position.x, position.y, position.z );
                cubeCamera.lookAt( position.x, position.y, position.z + forwardSign[ i ] );

            }

            const size = this._cubeSize;

            _setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );

            renderer.setRenderTarget( cubeUVRenderTarget );

            if ( useSolidColor ) {

                renderer.render( backgroundBox, cubeCamera );

            }

            renderer.render( scene, cubeCamera );

        }

        backgroundBox.geometry.dispose();
        backgroundBox.material.dispose();

        renderer.toneMapping = toneMapping;
        renderer.autoClear = originalAutoClear;
        scene.background = background;

    }
_textureToCubeUV(texture: any, cubeUVRenderTarget: any): void
Code
_textureToCubeUV( texture, cubeUVRenderTarget ) {

        const renderer = this._renderer;

        const isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );

        if ( isCubeTexture ) {

            if ( this._cubemapMaterial === null ) {

                this._cubemapMaterial = _getCubemapMaterial();

            }

            this._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? -1 : 1;

        } else {

            if ( this._equirectMaterial === null ) {

                this._equirectMaterial = _getEquirectMaterial();

            }

        }

        const material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;
        const mesh = new Mesh( this._lodPlanes[ 0 ], material );

        const uniforms = material.uniforms;

        uniforms[ 'envMap' ].value = texture;

        const size = this._cubeSize;

        _setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );

        renderer.setRenderTarget( cubeUVRenderTarget );
        renderer.render( mesh, _flatCamera );

    }
_applyPMREM(cubeUVRenderTarget: any): void
Code
_applyPMREM( cubeUVRenderTarget ) {

        const renderer = this._renderer;
        const autoClear = renderer.autoClear;
        renderer.autoClear = false;
        const n = this._lodPlanes.length;

        for ( let i = 1; i < n; i ++ ) {

            const sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );

            const poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];

            this._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );

        }

        renderer.autoClear = autoClear;

    }
_blur(cubeUVRenderTarget: WebGLRenderTarget, lodIn: number, lodOut: number, sigma: number, poleAxis: Vector3): void
Code
_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {

        const pingPongRenderTarget = this._pingPongRenderTarget;

        this._halfBlur(
            cubeUVRenderTarget,
            pingPongRenderTarget,
            lodIn,
            lodOut,
            sigma,
            'latitudinal',
            poleAxis );

        this._halfBlur(
            pingPongRenderTarget,
            cubeUVRenderTarget,
            lodOut,
            lodOut,
            sigma,
            'longitudinal',
            poleAxis );

    }
_halfBlur(targetIn: any, targetOut: any, lodIn: any, lodOut: any, sigmaRadians: any, direction: any, poleAxis: any): void
Code
_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {

        const renderer = this._renderer;
        const blurMaterial = this._blurMaterial;

        if ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {

            console.error(
                'blur direction must be either latitudinal or longitudinal!' );

        }

        // Number of standard deviations at which to cut off the discrete approximation.
        const STANDARD_DEVIATIONS = 3;

        const blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );
        const blurUniforms = blurMaterial.uniforms;

        const pixels = this._sizeLods[ lodIn ] - 1;
        const radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );
        const sigmaPixels = sigmaRadians / radiansPerPixel;
        const samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;

        if ( samples > MAX_SAMPLES ) {

            console.warn( `sigmaRadians, ${
                sigmaRadians}, is too large and will clip, as it requested ${
                samples} samples when the maximum is set to ${MAX_SAMPLES}` );

        }

        const weights = [];
        let sum = 0;

        for ( let i = 0; i < MAX_SAMPLES; ++ i ) {

            const x = i / sigmaPixels;
            const weight = Math.exp( - x * x / 2 );
            weights.push( weight );

            if ( i === 0 ) {

                sum += weight;

            } else if ( i < samples ) {

                sum += 2 * weight;

            }

        }

        for ( let i = 0; i < weights.length; i ++ ) {

            weights[ i ] = weights[ i ] / sum;

        }

        blurUniforms[ 'envMap' ].value = targetIn.texture;
        blurUniforms[ 'samples' ].value = samples;
        blurUniforms[ 'weights' ].value = weights;
        blurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';

        if ( poleAxis ) {

            blurUniforms[ 'poleAxis' ].value = poleAxis;

        }

        const { _lodMax } = this;
        blurUniforms[ 'dTheta' ].value = radiansPerPixel;
        blurUniforms[ 'mipInt' ].value = _lodMax - lodIn;

        const outputSize = this._sizeLods[ lodOut ];
        const x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );
        const y = 4 * ( this._cubeSize - outputSize );

        _setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );
        renderer.setRenderTarget( targetOut );
        renderer.render( blurMesh, _flatCamera );

    }

SingleUniform

Class Code
class SingleUniform {

    constructor( id, activeInfo, addr ) {

        this.id = id;
        this.addr = addr;
        this.cache = [];
        this.type = activeInfo.type;
        this.setValue = getSingularSetter( activeInfo.type );

        // this.path = activeInfo.name; // DEBUG

    }

}

PureArrayUniform

Class Code
class PureArrayUniform {

    constructor( id, activeInfo, addr ) {

        this.id = id;
        this.addr = addr;
        this.cache = [];
        this.type = activeInfo.type;
        this.size = activeInfo.size;
        this.setValue = getPureArraySetter( activeInfo.type );

        // this.path = activeInfo.name; // DEBUG

    }

}

StructuredUniform

Class Code
class StructuredUniform {

    constructor( id ) {

        this.id = id;

        this.seq = [];
        this.map = {};

    }

    setValue( gl, value, textures ) {

        const seq = this.seq;

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            u.setValue( gl, value[ u.id ], textures );

        }

    }

}

Methods

setValue(gl: any, value: any, textures: any): void
Code
setValue( gl, value, textures ) {

        const seq = this.seq;

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            u.setValue( gl, value[ u.id ], textures );

        }

    }

WebGLUniforms

Class Code
class WebGLUniforms {

    constructor( gl, program ) {

        this.seq = [];
        this.map = {};

        const n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );

        for ( let i = 0; i < n; ++ i ) {

            const info = gl.getActiveUniform( program, i ),
                addr = gl.getUniformLocation( program, info.name );

            parseUniform( info, addr, this );

        }

    }

    setValue( gl, name, value, textures ) {

        const u = this.map[ name ];

        if ( u !== undefined ) u.setValue( gl, value, textures );

    }

    setOptional( gl, object, name ) {

        const v = object[ name ];

        if ( v !== undefined ) this.setValue( gl, name, v );

    }

    static upload( gl, seq, values, textures ) {

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ],
                v = values[ u.id ];

            if ( v.needsUpdate !== false ) {

                // note: always updating when .needsUpdate is undefined
                u.setValue( gl, v.value, textures );

            }

        }

    }

    static seqWithValue( seq, values ) {

        const r = [];

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            if ( u.id in values ) r.push( u );

        }

        return r;

    }

}

Methods

setValue(gl: any, name: any, value: any, textures: any): void
Code
setValue( gl, name, value, textures ) {

        const u = this.map[ name ];

        if ( u !== undefined ) u.setValue( gl, value, textures );

    }
setOptional(gl: any, object: any, name: any): void
Code
setOptional( gl, object, name ) {

        const v = object[ name ];

        if ( v !== undefined ) this.setValue( gl, name, v );

    }
upload(gl: any, seq: any, values: any, textures: any): void
Code
static upload( gl, seq, values, textures ) {

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ],
                v = values[ u.id ];

            if ( v.needsUpdate !== false ) {

                // note: always updating when .needsUpdate is undefined
                u.setValue( gl, v.value, textures );

            }

        }

    }
seqWithValue(seq: any, values: any): any[]
Code
static seqWithValue( seq, values ) {

        const r = [];

        for ( let i = 0, n = seq.length; i !== n; ++ i ) {

            const u = seq[ i ];
            if ( u.id in values ) r.push( u );

        }

        return r;

    }

WebGLShaderCache

Class Code
class WebGLShaderCache {

    constructor() {

        this.shaderCache = new Map();
        this.materialCache = new Map();

    }

    update( material ) {

        const vertexShader = material.vertexShader;
        const fragmentShader = material.fragmentShader;

        const vertexShaderStage = this._getShaderStage( vertexShader );
        const fragmentShaderStage = this._getShaderStage( fragmentShader );

        const materialShaders = this._getShaderCacheForMaterial( material );

        if ( materialShaders.has( vertexShaderStage ) === false ) {

            materialShaders.add( vertexShaderStage );
            vertexShaderStage.usedTimes ++;

        }

        if ( materialShaders.has( fragmentShaderStage ) === false ) {

            materialShaders.add( fragmentShaderStage );
            fragmentShaderStage.usedTimes ++;

        }

        return this;

    }

    remove( material ) {

        const materialShaders = this.materialCache.get( material );

        for ( const shaderStage of materialShaders ) {

            shaderStage.usedTimes --;

            if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );

        }

        this.materialCache.delete( material );

        return this;

    }

    getVertexShaderID( material ) {

        return this._getShaderStage( material.vertexShader ).id;

    }

    getFragmentShaderID( material ) {

        return this._getShaderStage( material.fragmentShader ).id;

    }

    dispose() {

        this.shaderCache.clear();
        this.materialCache.clear();

    }

    _getShaderCacheForMaterial( material ) {

        const cache = this.materialCache;
        let set = cache.get( material );

        if ( set === undefined ) {

            set = new Set();
            cache.set( material, set );

        }

        return set;

    }

    _getShaderStage( code ) {

        const cache = this.shaderCache;
        let stage = cache.get( code );

        if ( stage === undefined ) {

            stage = new WebGLShaderStage( code );
            cache.set( code, stage );

        }

        return stage;

    }

}

Methods

update(material: any): this
Code
update( material ) {

        const vertexShader = material.vertexShader;
        const fragmentShader = material.fragmentShader;

        const vertexShaderStage = this._getShaderStage( vertexShader );
        const fragmentShaderStage = this._getShaderStage( fragmentShader );

        const materialShaders = this._getShaderCacheForMaterial( material );

        if ( materialShaders.has( vertexShaderStage ) === false ) {

            materialShaders.add( vertexShaderStage );
            vertexShaderStage.usedTimes ++;

        }

        if ( materialShaders.has( fragmentShaderStage ) === false ) {

            materialShaders.add( fragmentShaderStage );
            fragmentShaderStage.usedTimes ++;

        }

        return this;

    }
remove(material: any): this
Code
remove( material ) {

        const materialShaders = this.materialCache.get( material );

        for ( const shaderStage of materialShaders ) {

            shaderStage.usedTimes --;

            if ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );

        }

        this.materialCache.delete( material );

        return this;

    }
getVertexShaderID(material: any): any
Code
getVertexShaderID( material ) {

        return this._getShaderStage( material.vertexShader ).id;

    }
getFragmentShaderID(material: any): any
Code
getFragmentShaderID( material ) {

        return this._getShaderStage( material.fragmentShader ).id;

    }
dispose(): void
Code
dispose() {

        this.shaderCache.clear();
        this.materialCache.clear();

    }
_getShaderCacheForMaterial(material: any): any
Code
_getShaderCacheForMaterial( material ) {

        const cache = this.materialCache;
        let set = cache.get( material );

        if ( set === undefined ) {

            set = new Set();
            cache.set( material, set );

        }

        return set;

    }
_getShaderStage(code: any): any
Code
_getShaderStage( code ) {

        const cache = this.shaderCache;
        let stage = cache.get( code );

        if ( stage === undefined ) {

            stage = new WebGLShaderStage( code );
            cache.set( code, stage );

        }

        return stage;

    }

WebGLShaderStage

Class Code
class WebGLShaderStage {

    constructor( code ) {

        this.id = _id ++;

        this.code = code;
        this.usedTimes = 0;

    }

}

ExternalTexture

Class Code
class ExternalTexture extends Texture {

    /**
     * Creates a new raw texture.
     *
     * @param {?WebGLTexture} [sourceTexture=null] - The external texture.
     */
    constructor( sourceTexture = null ) {

        super();

        /**
         * The external source texture.
         *
         * @type {?WebGLTexture}
         * @default null
         */
        this.sourceTexture = sourceTexture;

        /**
         * This flag can be used for type testing.
         *
         * @type {boolean}
         * @readonly
         * @default true
         */
        this.isExternalTexture = true;

    }

}

WebXRDepthSensing

Class Code
class WebXRDepthSensing {

    /**
     * Constructs a new depth sensing module.
     */
    constructor() {

        /**
         * An opaque texture representing the depth of the user's environment.
         *
         * @type {?ExternalTexture}
         */
        this.texture = null;

        /**
         * A plane mesh for visualizing the depth texture.
         *
         * @type {?Mesh}
         */
        this.mesh = null;

        /**
         * The depth near value.
         *
         * @type {number}
         */
        this.depthNear = 0;

        /**
         * The depth near far.
         *
         * @type {number}
         */
        this.depthFar = 0;

    }

    /**
     * Inits the depth sensing module
     *
     * @param {XRWebGLDepthInformation} depthData - The XR depth data.
     * @param {XRRenderState} renderState - The XR render state.
     */
    init( depthData, renderState ) {

        if ( this.texture === null ) {

            const texture = new ExternalTexture( depthData.texture );

            if ( ( depthData.depthNear !== renderState.depthNear ) || ( depthData.depthFar !== renderState.depthFar ) ) {

                this.depthNear = depthData.depthNear;
                this.depthFar = depthData.depthFar;

            }

            this.texture = texture;

        }

    }

    /**
     * Returns a plane mesh that visualizes the depth texture.
     *
     * @param {ArrayCamera} cameraXR - The XR camera.
     * @return {?Mesh} The plane mesh.
     */
    getMesh( cameraXR ) {

        if ( this.texture !== null ) {

            if ( this.mesh === null ) {

                const viewport = cameraXR.cameras[ 0 ].viewport;
                const material = new ShaderMaterial( {
                    vertexShader: _occlusion_vertex,
                    fragmentShader: _occlusion_fragment,
                    uniforms: {
                        depthColor: { value: this.texture },
                        depthWidth: { value: viewport.z },
                        depthHeight: { value: viewport.w }
                    }
                } );

                this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material );

            }

        }

        return this.mesh;

    }

    /**
     * Resets the module
     */
    reset() {

        this.texture = null;
        this.mesh = null;

    }

    /**
     * Returns a texture representing the depth of the user's environment.
     *
     * @return {?ExternalTexture} The depth texture.
     */
    getDepthTexture() {

        return this.texture;

    }

}

Methods

init(depthData: XRWebGLDepthInformation, renderState: XRRenderState): void
Code
init( depthData, renderState ) {

        if ( this.texture === null ) {

            const texture = new ExternalTexture( depthData.texture );

            if ( ( depthData.depthNear !== renderState.depthNear ) || ( depthData.depthFar !== renderState.depthFar ) ) {

                this.depthNear = depthData.depthNear;
                this.depthFar = depthData.depthFar;

            }

            this.texture = texture;

        }

    }
getMesh(cameraXR: ArrayCamera): Mesh
Code
getMesh( cameraXR ) {

        if ( this.texture !== null ) {

            if ( this.mesh === null ) {

                const viewport = cameraXR.cameras[ 0 ].viewport;
                const material = new ShaderMaterial( {
                    vertexShader: _occlusion_vertex,
                    fragmentShader: _occlusion_fragment,
                    uniforms: {
                        depthColor: { value: this.texture },
                        depthWidth: { value: viewport.z },
                        depthHeight: { value: viewport.w }
                    }
                } );

                this.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material );

            }

        }

        return this.mesh;

    }
reset(): void
Code
reset() {

        this.texture = null;
        this.mesh = null;

    }
getDepthTexture(): ExternalTexture
Code
getDepthTexture() {

        return this.texture;

    }

WebXRManager

Class Code
class WebXRManager extends EventDispatcher {

    /**
     * Constructs a new WebGL renderer.
     *
     * @param {WebGLRenderer} renderer - The renderer.
     * @param {WebGL2RenderingContext} gl - The rendering context.
     */
    constructor( renderer, gl ) {

        super();

        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;
        let glBinding = null;
        let glProjLayer = null;
        let glBaseLayer = null;
        let xrFrame = null;

        const depthSensing = new WebXRDepthSensing();
        const cameraAccessTextures = {};
        const attributes = gl.getContextAttributes();

        let initialRenderTarget = null;
        let newRenderTarget = null;

        const controllers = [];
        const controllerInputSources = [];

        const currentSize = new Vector2();
        let currentPixelRatio = null;

        //

        const cameraL = new PerspectiveCamera();
        cameraL.viewport = new Vector4();

        const cameraR = new PerspectiveCamera();
        cameraR.viewport = new Vector4();

        const cameras = [ cameraL, cameraR ];

        const cameraXR = new ArrayCamera();

        let _currentDepthNear = null;
        let _currentDepthFar = null;

        //

        /**
         * Whether the manager's XR camera should be automatically updated or not.
         *
         * @type {boolean}
         * @default true
         */
        this.cameraAutoUpdate = true;

        /**
         * This flag notifies the renderer to be ready for XR rendering. Set it to `true`
         * if you are going to use XR in your app.
         *
         * @type {boolean}
         * @default false
         */
        this.enabled = false;

        /**
         * Whether XR presentation is active or not.
         *
         * @type {boolean}
         * @readonly
         * @default false
         */
        this.isPresenting = false;

        /**
         * Returns a group representing the `target ray` space of the XR controller.
         * Use this space for visualizing 3D objects that support the user in pointing
         * tasks like UI interaction.
         *
         * @param {number} index - The index of the controller.
         * @return {Group} A group representing the `target ray` space.
         */
        this.getController = function ( index ) {

            let controller = controllers[ index ];

            if ( controller === undefined ) {

                controller = new WebXRController();
                controllers[ index ] = controller;

            }

            return controller.getTargetRaySpace();

        };

        /**
         * Returns a group representing the `grip` space of the XR controller.
         * Use this space for visualizing 3D objects that support the user in pointing
         * tasks like UI interaction.
         *
         * Note: If you want to show something in the user's hand AND offer a
         * pointing ray at the same time, you'll want to attached the handheld object
         * to the group returned by `getControllerGrip()` and the ray to the
         * group returned by `getController()`. The idea is to have two
         * different groups in two different coordinate spaces for the same WebXR
         * controller.
         *
         * @param {number} index - The index of the controller.
         * @return {Group} A group representing the `grip` space.
         */
        this.getControllerGrip = function ( index ) {

            let controller = controllers[ index ];

            if ( controller === undefined ) {

                controller = new WebXRController();
                controllers[ index ] = controller;

            }

            return controller.getGripSpace();

        };

        /**
         * Returns a group representing the `hand` space of the XR controller.
         * Use this space for visualizing 3D objects that support the user in pointing
         * tasks like UI interaction.
         *
         * @param {number} index - The index of the controller.
         * @return {Group} A group representing the `hand` space.
         */
        this.getHand = function ( index ) {

            let controller = controllers[ index ];

            if ( controller === undefined ) {

                controller = new WebXRController();
                controllers[ index ] = controller;

            }

            return controller.getHandSpace();

        };

        //

        function onSessionEvent( event ) {

            const controllerIndex = controllerInputSources.indexOf( event.inputSource );

            if ( controllerIndex === -1 ) {

                return;

            }

            const controller = controllers[ controllerIndex ];

            if ( controller !== undefined ) {

                controller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );
                controller.dispatchEvent( { type: event.type, data: event.inputSource } );

            }

        }

        function onSessionEnd() {

            session.removeEventListener( 'select', onSessionEvent );
            session.removeEventListener( 'selectstart', onSessionEvent );
            session.removeEventListener( 'selectend', onSessionEvent );
            session.removeEventListener( 'squeeze', onSessionEvent );
            session.removeEventListener( 'squeezestart', onSessionEvent );
            session.removeEventListener( 'squeezeend', onSessionEvent );
            session.removeEventListener( 'end', onSessionEnd );
            session.removeEventListener( 'inputsourceschange', onInputSourcesChange );

            for ( let i = 0; i < controllers.length; i ++ ) {

                const inputSource = controllerInputSources[ i ];

                if ( inputSource === null ) continue;

                controllerInputSources[ i ] = null;

                controllers[ i ].disconnect( inputSource );

            }

            _currentDepthNear = null;
            _currentDepthFar = null;

            depthSensing.reset();
            for ( const key in cameraAccessTextures ) {

                delete cameraAccessTextures[ key ];

            }

            // restore framebuffer/rendering state

            renderer.setRenderTarget( initialRenderTarget );

            glBaseLayer = null;
            glProjLayer = null;
            glBinding = null;
            session = null;
            newRenderTarget = null;

            //

            animation.stop();

            scope.isPresenting = false;

            renderer.setPixelRatio( currentPixelRatio );
            renderer.setSize( currentSize.width, currentSize.height, false );

            scope.dispatchEvent( { type: 'sessionend' } );

        }

        /**
         * Sets the framebuffer scale factor.
         *
         * This method can not be used during a XR session.
         *
         * @param {number} value - The framebuffer scale factor.
         */
        this.setFramebufferScaleFactor = function ( value ) {

            framebufferScaleFactor = value;

            if ( scope.isPresenting === true ) {

                console.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );

            }

        };

        /**
         * Sets the reference space type. Can be used to configure a spatial relationship with the user's physical
         * environment. Depending on how the user moves in 3D space, setting an appropriate reference space can
         * improve tracking. Default is `local-floor`. Valid values can be found here
         * https://developer.mozilla.org/en-US/docs/Web/API/XRReferenceSpace#reference_space_types.
         *
         * This method can not be used during a XR session.
         *
         * @param {string} value - The reference space type.
         */
        this.setReferenceSpaceType = function ( value ) {

            referenceSpaceType = value;

            if ( scope.isPresenting === true ) {

                console.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );

            }

        };

        /**
         * Returns the XR reference space.
         *
         * @return {XRReferenceSpace} The XR reference space.
         */
        this.getReferenceSpace = function () {

            return customReferenceSpace || referenceSpace;

        };

        /**
         * Sets a custom XR reference space.
         *
         * @param {XRReferenceSpace} space - The XR reference space.
         */
        this.setReferenceSpace = function ( space ) {

            customReferenceSpace = space;

        };

        /**
         * Returns the current base layer.
         *
         * @return {?(XRWebGLLayer|XRProjectionLayer)} The XR base layer.
         */
        this.getBaseLayer = function () {

            return glProjLayer !== null ? glProjLayer : glBaseLayer;

        };

        /**
         * Returns the current XR binding.
         *
         * @return {?XRWebGLBinding} The XR binding.
         */
        this.getBinding = function () {

            return glBinding;

        };

        /**
         * Returns the current XR frame.
         *
         * @return {?XRFrame} The XR frame. Returns `null` when used outside a XR session.
         */
        this.getFrame = function () {

            return xrFrame;

        };

        /**
         * Returns the current XR session.
         *
         * @return {?XRSession} The XR session. Returns `null` when used outside a XR session.
         */
        this.getSession = function () {

            return session;

        };

        /**
         * After a XR session has been requested usually with one of the `*Button` modules, it
         * is injected into the renderer with this method. This method triggers the start of
         * the actual XR rendering.
         *
         * @async
         * @param {XRSession} value - The XR session to set.
         * @return {Promise} A Promise that resolves when the session has been set.
         */
        this.setSession = async function ( value ) {

            session = value;

            if ( session !== null ) {

                initialRenderTarget = renderer.getRenderTarget();

                session.addEventListener( 'select', onSessionEvent );
                session.addEventListener( 'selectstart', onSessionEvent );
                session.addEventListener( 'selectend', onSessionEvent );
                session.addEventListener( 'squeeze', onSessionEvent );
                session.addEventListener( 'squeezestart', onSessionEvent );
                session.addEventListener( 'squeezeend', onSessionEvent );
                session.addEventListener( 'end', onSessionEnd );
                session.addEventListener( 'inputsourceschange', onInputSourcesChange );

                if ( attributes.xrCompatible !== true ) {

                    await gl.makeXRCompatible();

                }

                currentPixelRatio = renderer.getPixelRatio();
                renderer.getSize( currentSize );

                if ( typeof XRWebGLBinding !== 'undefined' ) {

                    glBinding = new XRWebGLBinding( session, gl );

                }

                // Check that the browser implements the necessary APIs to use an
                // XRProjectionLayer rather than an XRWebGLLayer
                const useLayers = glBinding !== null && 'createProjectionLayer' in XRWebGLBinding.prototype;

                if ( ! useLayers ) {

                    const layerInit = {
                        antialias: attributes.antialias,
                        alpha: true,
                        depth: attributes.depth,
                        stencil: attributes.stencil,
                        framebufferScaleFactor: framebufferScaleFactor
                    };

                    glBaseLayer = new XRWebGLLayer( session, gl, layerInit );

                    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,
                            colorSpace: renderer.outputColorSpace,
                            stencilBuffer: attributes.stencil,
                            resolveDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ),
                            resolveStencilBuffer: ( glBaseLayer.ignoreDepthValues === false )

                        }
                    );

                } else {

                    let depthFormat = null;
                    let depthType = null;
                    let glDepthFormat = null;

                    if ( attributes.depth ) {

                        glDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;
                        depthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;
                        depthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType;

                    }

                    const projectionlayerInit = {
                        colorFormat: gl.RGBA8,
                        depthFormat: glDepthFormat,
                        scaleFactor: framebufferScaleFactor
                    };

                    glProjLayer = glBinding.createProjectionLayer( projectionlayerInit );

                    session.updateRenderState( { layers: [ glProjLayer ] } );

                    renderer.setPixelRatio( 1 );
                    renderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );

                    newRenderTarget = new WebGLRenderTarget(
                        glProjLayer.textureWidth,
                        glProjLayer.textureHeight,
                        {
                            format: RGBAFormat,
                            type: UnsignedByteType,
                            depthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),
                            stencilBuffer: attributes.stencil,
                            colorSpace: renderer.outputColorSpace,
                            samples: attributes.antialias ? 4 : 0,
                            resolveDepthBuffer: ( glProjLayer.ignoreDepthValues === false ),
                            resolveStencilBuffer: ( glProjLayer.ignoreDepthValues === false )
                        } );

                }

                newRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278

                this.setFoveation( foveation );

                customReferenceSpace = null;
                referenceSpace = await session.requestReferenceSpace( referenceSpaceType );

                animation.setContext( session );
                animation.start();

                scope.isPresenting = true;

                scope.dispatchEvent( { type: 'sessionstart' } );

            }

        };

        /**
         * Returns the environment blend mode from the current XR session.
         *
         * @return {'opaque'|'additive'|'alpha-blend'|undefined} The environment blend mode. Returns `undefined` when used outside of a XR session.
         */
        this.getEnvironmentBlendMode = function () {

            if ( session !== null ) {

                return session.environmentBlendMode;

            }

        };

        /**
         * Returns the current depth texture computed via depth sensing.
         *
         * @return {?Texture} The depth texture.
         */
        this.getDepthTexture = function () {

            return depthSensing.getDepthTexture();

        };

        function onInputSourcesChange( event ) {

            // Notify disconnected

            for ( let i = 0; i < event.removed.length; i ++ ) {

                const inputSource = event.removed[ i ];
                const index = controllerInputSources.indexOf( inputSource );

                if ( index >= 0 ) {

                    controllerInputSources[ index ] = null;
                    controllers[ index ].disconnect( inputSource );

                }

            }

            // Notify connected

            for ( let i = 0; i < event.added.length; i ++ ) {

                const inputSource = event.added[ i ];

                let controllerIndex = controllerInputSources.indexOf( inputSource );

                if ( controllerIndex === -1 ) {

                    // Assign input source a controller that currently has no input source

                    for ( let i = 0; i < controllers.length; i ++ ) {

                        if ( i >= controllerInputSources.length ) {

                            controllerInputSources.push( inputSource );
                            controllerIndex = i;
                            break;

                        } else if ( controllerInputSources[ i ] === null ) {

                            controllerInputSources[ i ] = inputSource;
                            controllerIndex = i;
                            break;

                        }

                    }

                    // If all controllers do currently receive input we ignore new ones

                    if ( controllerIndex === -1 ) break;

                }

                const controller = controllers[ controllerIndex ];

                if ( controller ) {

                    controller.connect( inputSource );

                }

            }

        }

        //

        const cameraLPos = new Vector3();
        const cameraRPos = new Vector3();

        /**
         * Assumes 2 cameras that are parallel and share an X-axis, and that
         * the cameras' projection and world matrices have already been set.
         * And that near and far planes are identical for both cameras.
         * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765
         *
         * @param {ArrayCamera} camera - The camera to update.
         * @param {PerspectiveCamera} cameraL - The left camera.
         * @param {PerspectiveCamera} cameraR - The right camera.
         */
        function setProjectionFromUnion( camera, cameraL, cameraR ) {

            cameraLPos.setFromMatrixPosition( cameraL.matrixWorld );
            cameraRPos.setFromMatrixPosition( cameraR.matrixWorld );

            const ipd = cameraLPos.distanceTo( cameraRPos );

            const projL = cameraL.projectionMatrix.elements;
            const projR = cameraR.projectionMatrix.elements;

            // VR systems will have identical far and near planes, and
            // most likely identical top and bottom frustum extents.
            // Use the left camera for these values.
            const near = projL[ 14 ] / ( projL[ 10 ] - 1 );
            const far = projL[ 14 ] / ( projL[ 10 ] + 1 );
            const topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];
            const bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];

            const leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];
            const rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];
            const left = near * leftFov;
            const right = near * rightFov;

            // Calculate the new camera's position offset from the
            // left camera. xOffset should be roughly half `ipd`.
            const zOffset = ipd / ( - leftFov + rightFov );
            const xOffset = zOffset * - leftFov;

            // TODO: Better way to apply this offset?
            cameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );
            camera.translateX( xOffset );
            camera.translateZ( zOffset );
            camera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );
            camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();

            // Check if the projection uses an infinite far plane.
            if ( projL[ 10 ] === -1 ) {

                // Use the projection matrix from the left eye.
                // The camera offset is sufficient to include the view volumes
                // of both eyes (assuming symmetric projections).
                camera.projectionMatrix.copy( cameraL.projectionMatrix );
                camera.projectionMatrixInverse.copy( cameraL.projectionMatrixInverse );

            } else {

                // Find the union of the frustum values of the cameras and scale
                // the values so that the near plane's position does not change in world space,
                // although must now be relative to the new union camera.
                const near2 = near + zOffset;
                const far2 = far + zOffset;
                const left2 = left - xOffset;
                const right2 = right + ( ipd - xOffset );
                const top2 = topFov * far / far2 * near2;
                const bottom2 = bottomFov * far / far2 * near2;

                camera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );
                camera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();

            }

        }

        function updateCamera( camera, parent ) {

            if ( parent === null ) {

                camera.matrixWorld.copy( camera.matrix );

            } else {

                camera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );

            }

            camera.matrixWorldInverse.copy( camera.matrixWorld ).invert();

        }

        /**
         * Updates the state of the XR camera. Use this method on app level if you
         * set cameraAutoUpdate` to `false`. The method requires the non-XR
         * camera of the scene as a parameter. The passed in camera's transformation
         * is automatically adjusted to the position of the XR camera when calling
         * this method.
         *
         * @param {Camera} camera - The camera.
         */
        this.updateCamera = function ( camera ) {

            if ( session === null ) return;

            let depthNear = camera.near;
            let depthFar = camera.far;

            if ( depthSensing.texture !== null ) {

                if ( depthSensing.depthNear > 0 ) depthNear = depthSensing.depthNear;
                if ( depthSensing.depthFar > 0 ) depthFar = depthSensing.depthFar;

            }

            cameraXR.near = cameraR.near = cameraL.near = depthNear;
            cameraXR.far = cameraR.far = cameraL.far = depthFar;

            if ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {

                // Note that the new renderState won't apply until the next frame. See #18320

                session.updateRenderState( {
                    depthNear: cameraXR.near,
                    depthFar: cameraXR.far
                } );

                _currentDepthNear = cameraXR.near;
                _currentDepthFar = cameraXR.far;

            }

            // inherit camera layers and enable eye layers (1 = left, 2 = right)
            cameraXR.layers.mask = camera.layers.mask | 0b110;
            cameraL.layers.mask = cameraXR.layers.mask & 0b011;
            cameraR.layers.mask = cameraXR.layers.mask & 0b101;

            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 ) {

                setProjectionFromUnion( cameraXR, cameraL, cameraR );

            } else {

                // assume single camera setup (AR)

                cameraXR.projectionMatrix.copy( cameraL.projectionMatrix );

            }

            // update user camera and its children

            updateUserCamera( camera, cameraXR, parent );

        };

        function updateUserCamera( camera, cameraXR, parent ) {

            if ( parent === null ) {

                camera.matrix.copy( cameraXR.matrixWorld );

            } else {

                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 );

            if ( camera.isPerspectiveCamera ) {

                camera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );
                camera.zoom = 1;

            }

        }

        /**
         * Returns an instance of {@link ArrayCamera} which represents the XR camera
         * of the active XR session. For each view it holds a separate camera object.
         *
         * The camera's `fov` is currently not used and does not reflect the fov of
         * the XR camera. If you need the fov on app level, you have to compute in
         * manually from the XR camera's projection matrices.
         *
         * @return {ArrayCamera} The XR camera.
         */
        this.getCamera = function () {

            return cameraXR;

        };

        /**
         * Returns the amount of foveation used by the XR compositor for the projection layer.
         *
         * @return {number|undefined} The amount of foveation.
         */
        this.getFoveation = function () {

            if ( glProjLayer === null && glBaseLayer === null ) {

                return undefined;

            }

            return foveation;

        };

        /**
         * Sets the foveation value.
         *
         * @param {number} value - A number in the range `[0,1]` where `0` means no foveation (full resolution)
         * and `1` means maximum foveation (the edges render at lower resolution).
         */
        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 = value;

            }

            if ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {

                glBaseLayer.fixedFoveation = value;

            }

        };

        /**
         * Returns `true` if depth sensing is supported.
         *
         * @return {boolean} Whether depth sensing is supported or not.
         */
        this.hasDepthSensing = function () {

            return depthSensing.texture !== null;

        };

        /**
         * Returns the depth sensing mesh.
         *
         * @return {Mesh} The depth sensing mesh.
         */
        this.getDepthSensingMesh = function () {

            return depthSensing.getMesh( cameraXR );

        };

        /**
         * Retrieves an opaque texture from the view-aligned {@link XRCamera}.
         * Only available during the current animation loop.
         *
         * @param {XRCamera} xrCamera - The camera to query.
         * @return {?Texture} An opaque texture representing the current raw camera frame.
         */
        this.getCameraTexture = function ( xrCamera ) {

            return cameraAccessTextures[ xrCamera ];

        };

        // Animation Loop

        let onAnimationFrameCallback = null;

        function onAnimationFrame( time, frame ) {

            pose = frame.getViewerPose( customReferenceSpace || referenceSpace );
            xrFrame = frame;

            if ( pose !== null ) {

                const views = pose.views;

                if ( glBaseLayer !== null ) {

                    renderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );
                    renderer.setRenderTarget( newRenderTarget );

                }

                let cameraXRNeedsUpdate = false;

                // check if it's necessary to rebuild cameraXR's camera list

                if ( views.length !== cameraXR.cameras.length ) {

                    cameraXR.cameras.length = 0;
                    cameraXRNeedsUpdate = true;

                }

                for ( let i = 0; i < views.length; i ++ ) {

                    const view = views[ i ];

                    let viewport = null;

                    if ( glBaseLayer !== null ) {

                        viewport = glBaseLayer.getViewport( view );

                    } else {

                        const glSubImage = glBinding.getViewSubImage( glProjLayer, view );
                        viewport = glSubImage.viewport;

                        // For side-by-side projection, we only produce a single texture for both eyes.
                        if ( i === 0 ) {

                            renderer.setRenderTargetTextures(
                                newRenderTarget,
                                glSubImage.colorTexture,
                                glSubImage.depthStencilTexture );

                            renderer.setRenderTarget( newRenderTarget );

                        }

                    }

                    let camera = cameras[ i ];

                    if ( camera === undefined ) {

                        camera = new PerspectiveCamera();
                        camera.layers.enable( i );
                        camera.viewport = new Vector4();
                        cameras[ i ] = camera;

                    }

                    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 ) {

                        cameraXR.matrix.copy( camera.matrix );
                        cameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );

                    }

                    if ( cameraXRNeedsUpdate === true ) {

                        cameraXR.cameras.push( camera );

                    }

                }

                //

                const enabledFeatures = session.enabledFeatures;
                const gpuDepthSensingEnabled = enabledFeatures &&
                    enabledFeatures.includes( 'depth-sensing' ) &&
                    session.depthUsage == 'gpu-optimized';

                if ( gpuDepthSensingEnabled && glBinding ) {

                    const depthData = glBinding.getDepthInformation( views[ 0 ] );

                    if ( depthData && depthData.isValid && depthData.texture ) {

                        depthSensing.init( depthData, session.renderState );

                    }

                }

                const cameraAccessEnabled = enabledFeatures &&
                    enabledFeatures.includes( 'camera-access' );

                if ( cameraAccessEnabled ) {

                    renderer.state.unbindTexture();

                    if ( glBinding ) {

                        for ( let i = 0; i < views.length; i ++ ) {

                            const camera = views[ i ].camera;

                            if ( camera ) {

                                let cameraTex = cameraAccessTextures[ camera ];

                                if ( ! cameraTex ) {

                                    cameraTex = new ExternalTexture();
                                    cameraAccessTextures[ camera ] = cameraTex;

                                }

                                const glTexture = glBinding.getCameraImage( camera );
                                cameraTex.sourceTexture = glTexture;

                            }

                        }

                    }

                }

            }

            //

            for ( let i = 0; i < controllers.length; i ++ ) {

                const inputSource = controllerInputSources[ i ];
                const controller = controllers[ i ];

                if ( inputSource !== null && controller !== undefined ) {

                    controller.update( inputSource, frame, customReferenceSpace || referenceSpace );

                }

            }

            if ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );

            if ( frame.detectedPlanes ) {

                scope.dispatchEvent( { type: 'planesdetected', data: frame } );

            }

            xrFrame = null;

        }

        const animation = new WebGLAnimation();

        animation.setAnimationLoop( onAnimationFrame );

        this.setAnimationLoop = function ( callback ) {

            onAnimationFrameCallback = callback;

        };

        this.dispose = function () {};

    }

}

WebGLRenderer

Class Code
class WebGLRenderer {

    /**
     * Constructs a new WebGL renderer.
     *
     * @param {WebGLRenderer~Options} [parameters] - The configuration parameter.
     */
    constructor( parameters = {} ) {

        const {
            canvas = createCanvasElement(),
            context = null,
            depth = true,
            stencil = false,
            alpha = false,
            antialias = false,
            premultipliedAlpha = true,
            preserveDrawingBuffer = false,
            powerPreference = 'default',
            failIfMajorPerformanceCaveat = false,
            reversedDepthBuffer = false,
        } = parameters;

        /**
         * This flag can be used for type testing.
         *
         * @type {boolean}
         * @readonly
         * @default true
         */
        this.isWebGLRenderer = true;

        let _alpha;

        if ( context !== null ) {

            if ( typeof WebGLRenderingContext !== 'undefined' && context instanceof WebGLRenderingContext ) {

                throw new Error( 'THREE.WebGLRenderer: WebGL 1 is not supported since r163.' );

            }

            _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

        /**
         * A canvas where the renderer draws its output.This is automatically created by the renderer
         * in the constructor (if not provided already); you just need to add it to your page like so:
         * ```js
         * document.body.appendChild( renderer.domElement );
         * ```
         *
         * @type {DOMElement}
         */
        this.domElement = canvas;

        /**
         * A object with debug configuration settings.
         *
         * - `checkShaderErrors`: If it is `true`, defines whether material shader programs are
         * checked for errors during compilation and linkage process. It may be useful to disable
         * this check in production for performance gain. It is strongly recommended to keep these
         * checks enabled during development. If the shader does not compile and link - it will not
         * work and associated material will not render.
         * - `onShaderError(gl, program, glVertexShader,glFragmentShader)`: A callback function that
         * can be used for custom error reporting. The callback receives the WebGL context, an instance
         * of WebGLProgram as well two instances of WebGLShader representing the vertex and fragment shader.
         * Assigning a custom function disables the default error reporting.
         *
         * @type {Object}
         */
        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

        /**
         * Whether the renderer should automatically clear its output before rendering a frame or not.
         *
         * @type {boolean}
         * @default true
         */
        this.autoClear = true;

        /**
         * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear
         * the color buffer or not.
         *
         * @type {boolean}
         * @default true
         */
        this.autoClearColor = true;

        /**
         * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear
         * the depth buffer or not.
         *
         * @type {boolean}
         * @default true
         */
        this.autoClearDepth = true;

        /**
         * If {@link WebGLRenderer#autoClear} set to `true`, whether the renderer should clear
         * the stencil buffer or not.
         *
         * @type {boolean}
         * @default true
         */
        this.autoClearStencil = true;

        // scene graph

        /**
         * Whether the renderer should sort objects or not.
         *
         * Note: Sorting is used to attempt to properly render objects that have some
         * degree of transparency. By definition, sorting objects may not work in all
         * cases. Depending on the needs of application, it may be necessary to turn
         * off sorting and use other methods to deal with transparency rendering e.g.
         * manually determining each object's rendering order.
         *
         * @type {boolean}
         * @default true
         */
        this.sortObjects = true;

        // user-defined clipping

        /**
         * User-defined clipping planes specified in world space. These planes apply globally.
         * Points in space whose dot product with the plane is negative are cut away.
         *
         * @type {Array<Plane>}
         */
        this.clippingPlanes = [];

        /**
         * Whether the renderer respects object-level clipping planes or not.
         *
         * @type {boolean}
         * @default false
         */
        this.localClippingEnabled = false;

        // tone mapping

        /**
         * The tone mapping technique of the renderer.
         *
         * @type {(NoToneMapping|LinearToneMapping|ReinhardToneMapping|CineonToneMapping|ACESFilmicToneMapping|CustomToneMapping|AgXToneMapping|NeutralToneMapping)}
         * @default NoToneMapping
         */
        this.toneMapping = NoToneMapping;

        /**
         * Exposure level of tone mapping.
         *
         * @type {number}
         * @default 1
         */
        this.toneMappingExposure = 1.0;

        // transmission

        /**
         * The normalized resolution scale for the transmission render target, measured in percentage
         * of viewport dimensions. Lowering this value can result in significant performance improvements
         * when using {@link MeshPhysicalMaterial#transmission}.
         *
         * @type {number}
         * @default 1
         */
        this.transmissionResolutionScale = 1.0;

        // internal properties

        const _this = this;

        let _isContextLost = false;

        // internal state cache

        this._outputColorSpace = SRGBColorSpace;

        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;

        // camera matrices cache

        const _projScreenMatrix = new Matrix4();

        const _vector3 = new Vector3();

        const _vector4 = new Vector4();

        const _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };

        let _renderBackground = false;

        function getTargetPixelRatio() {

            return _currentRenderTarget === null ? _pixelRatio : 1;

        }

        // initialize

        let _gl = context;

        function getContext( contextName, contextAttributes ) {

            return canvas.getContext( contextName, contextAttributes );

        }

        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 contextName = 'webgl2';

                _gl = getContext( contextName, contextAttributes );

                if ( _gl === null ) {

                    if ( getContext( contextName ) ) {

                        throw new Error( 'Error creating WebGL context with your selected attributes.' );

                    } else {

                        throw new Error( 'Error creating WebGL context.' );

                    }

                }

            }

        } catch ( error ) {

            console.error( 'THREE.WebGLRenderer: ' + error.message );
            throw error;

        }

        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;

        let utils, bindingStates, uniformsGroups;

        function initGLContext() {

            extensions = new WebGLExtensions( _gl );
            extensions.init();

            utils = new WebGLUtils( _gl, extensions );

            capabilities = new WebGLCapabilities( _gl, extensions, parameters, utils );

            state = new WebGLState( _gl, extensions );

            if ( capabilities.reversedDepthBuffer && reversedDepthBuffer ) {

                state.buffers.depth.setReversed( true );

            }

            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 );
            bindingStates = new WebGLBindingStates( _gl, attributes );
            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 );
            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 );
            indexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );

            info.programs = programCache.programs;

            /**
             * Holds details about the capabilities of the current rendering context.
             *
             * @name WebGLRenderer#capabilities
             * @type {WebGLRenderer~Capabilities}
             */
            _this.capabilities = capabilities;

            /**
             * Provides methods for retrieving and testing WebGL extensions.
             *
             * - `get(extensionName:string)`: Used to check whether a WebGL extension is supported
             * and return the extension object if available.
             * - `has(extensionName:string)`: returns `true` if the extension is supported.
             *
             * @name WebGLRenderer#extensions
             * @type {Object}
             */
            _this.extensions = extensions;

            /**
             * Used to track properties of other objects like native WebGL objects.
             *
             * @name WebGLRenderer#properties
             * @type {Object}
             */
            _this.properties = properties;

            /**
             * Manages the render lists of the renderer.
             *
             * @name WebGLRenderer#renderLists
             * @type {Object}
             */
            _this.renderLists = renderLists;



            /**
             * Interface for managing shadows.
             *
             * @name WebGLRenderer#shadowMap
             * @type {WebGLRenderer~ShadowMap}
             */
            _this.shadowMap = shadowMap;

            /**
             * Interface for managing the WebGL state.
             *
             * @name WebGLRenderer#state
             * @type {Object}
             */
            _this.state = state;

            /**
             * Holds a series of statistical information about the GPU memory
             * and the rendering process. Useful for debugging and monitoring.
             *
             * By default these data are reset at each render call but when having
             * multiple render passes per frame (e.g. when using post processing) it can
             * be preferred to reset with a custom pattern. First, set `autoReset` to
             * `false`.
             * ```js
             * renderer.info.autoReset = false;
             * ```
             * Call `reset()` whenever you have finished to render a single frame.
             * ```js
             * renderer.info.reset();
             * ```
             *
             * @name WebGLRenderer#info
             * @type {WebGLRenderer~Info}
             */
            _this.info = info;

        }

        initGLContext();

        // xr

        const xr = new WebXRManager( _this, _gl );

        /**
         * A reference to the XR manager.
         *
         * @type {WebXRManager}
         */
        this.xr = xr;

        /**
         * Returns the rendering context.
         *
         * @return {WebGL2RenderingContext} The rendering context.
         */
        this.getContext = function () {

            return _gl;

        };

        /**
         * Returns the rendering context attributes.
         *
         * @return {WebGLContextAttributes} The rendering context attributes.
         */
        this.getContextAttributes = function () {

            return _gl.getContextAttributes();

        };

        /**
         * Simulates a loss of the WebGL context. This requires support for the `WEBGL_lose_context` extension.
         */
        this.forceContextLoss = function () {

            const extension = extensions.get( 'WEBGL_lose_context' );
            if ( extension ) extension.loseContext();

        };

        /**
         * Simulates a restore of the WebGL context. This requires support for the `WEBGL_lose_context` extension.
         */
        this.forceContextRestore = function () {

            const extension = extensions.get( 'WEBGL_lose_context' );
            if ( extension ) extension.restoreContext();

        };

        /**
         * Returns the pixel ratio.
         *
         * @return {number} The pixel ratio.
         */
        this.getPixelRatio = function () {

            return _pixelRatio;

        };

        /**
         * Sets the given pixel ratio and resizes the canvas if necessary.
         *
         * @param {number} value - The pixel ratio.
         */
        this.setPixelRatio = function ( value ) {

            if ( value === undefined ) return;

            _pixelRatio = value;

            this.setSize( _width, _height, false );

        };

        /**
         * Returns the renderer's size in logical pixels. This method does not honor the pixel ratio.
         *
         * @param {Vector2} target - The method writes the result in this target object.
         * @return {Vector2} The renderer's size in logical pixels.
         */
        this.getSize = function ( target ) {

            return target.set( _width, _height );

        };

        /**
         * Resizes the output canvas to (width, height) with device pixel ratio taken
         * into account, and also sets the viewport to fit that size, starting in (0,
         * 0). Setting `updateStyle` to false prevents any style changes to the output canvas.
         *
         * @param {number} width - The width in logical pixels.
         * @param {number} height - The height in logical pixels.
         * @param {boolean} [updateStyle=true] - Whether to update the `style` attribute of the canvas or not.
         */
        this.setSize = function ( width, height, updateStyle = true ) {

            if ( xr.isPresenting ) {

                console.warn( 'THREE.WebGLRenderer: Can\'t change size while VR device is presenting.' );
                return;

            }

            _width = width;
            _height = height;

            canvas.width = Math.floor( width * _pixelRatio );
            canvas.height = Math.floor( height * _pixelRatio );

            if ( updateStyle === true ) {

                canvas.style.width = width + 'px';
                canvas.style.height = height + 'px';

            }

            this.setViewport( 0, 0, width, height );

        };

        /**
         * Returns the drawing buffer size in physical pixels. This method honors the pixel ratio.
         *
         * @param {Vector2} target - The method writes the result in this target object.
         * @return {Vector2} The drawing buffer size.
         */
        this.getDrawingBufferSize = function ( target ) {

            return target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();

        };

        /**
         * This method allows to define the drawing buffer size by specifying
         * width, height and pixel ratio all at once. The size of the drawing
         * buffer is computed with this formula:
         * ```js
         * size.x = width * pixelRatio;
         * size.y = height * pixelRatio;
         * ```
         *
         * @param {number} width - The width in logical pixels.
         * @param {number} height - The height in logical pixels.
         * @param {number} pixelRatio - The pixel ratio.
         */
        this.setDrawingBufferSize = function ( width, height, pixelRatio ) {

            _width = width;
            _height = height;

            _pixelRatio = pixelRatio;

            canvas.width = Math.floor( width * pixelRatio );
            canvas.height = Math.floor( height * pixelRatio );

            this.setViewport( 0, 0, width, height );

        };

        /**
         * Returns the current viewport definition.
         *
         * @param {Vector2} target - The method writes the result in this target object.
         * @return {Vector2} The current viewport definition.
         */
        this.getCurrentViewport = function ( target ) {

            return target.copy( _currentViewport );

        };

        /**
         * Returns the viewport definition.
         *
         * @param {Vector4} target - The method writes the result in this target object.
         * @return {Vector4} The viewport definition.
         */
        this.getViewport = function ( target ) {

            return target.copy( _viewport );

        };

        /**
         * Sets the viewport to render from `(x, y)` to `(x + width, y + height)`.
         *
         * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the viewport origin in logical pixel unit.
         * Or alternatively a four-component vector specifying all the parameters of the viewport.
         * @param {number} y - The vertical coordinate for the lower left corner of the viewport origin  in logical pixel unit.
         * @param {number} width - The width of the viewport in logical pixel unit.
         * @param {number} height - The height of the viewport in logical pixel unit.
         */
        this.setViewport = function ( x, y, width, height ) {

            if ( x.isVector4 ) {

                _viewport.set( x.x, x.y, x.z, x.w );

            } else {

                _viewport.set( x, y, width, height );

            }

            state.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).round() );

        };

        /**
         * Returns the scissor region.
         *
         * @param {Vector4} target - The method writes the result in this target object.
         * @return {Vector4} The scissor region.
         */
        this.getScissor = function ( target ) {

            return target.copy( _scissor );

        };

        /**
         * Sets the scissor region to render from `(x, y)` to `(x + width, y + height)`.
         *
         * @param {number | Vector4} x - The horizontal coordinate for the lower left corner of the scissor region origin in logical pixel unit.
         * Or alternatively a four-component vector specifying all the parameters of the scissor region.
         * @param {number} y - The vertical coordinate for the lower left corner of the scissor region origin  in logical pixel unit.
         * @param {number} width - The width of the scissor region in logical pixel unit.
         * @param {number} height - The height of the scissor region in logical pixel unit.
         */
        this.setScissor = function ( x, y, width, height ) {

            if ( x.isVector4 ) {

                _scissor.set( x.x, x.y, x.z, x.w );

            } else {

                _scissor.set( x, y, width, height );

            }

            state.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).round() );

        };

        /**
         * Returns `true` if the scissor test is enabled.
         *
         * @return {boolean} Whether the scissor test is enabled or not.
         */
        this.getScissorTest = function () {

            return _scissorTest;

        };

        /**
         * Enable or disable the scissor test. When this is enabled, only the pixels
         * within the defined scissor area will be affected by further renderer
         * actions.
         *
         * @param {boolean} boolean - Whether the scissor test is enabled or not.
         */
        this.setScissorTest = function ( boolean ) {

            state.setScissorTest( _scissorTest = boolean );

        };

        /**
         * Sets a custom opaque sort function for the render lists. Pass `null`
         * to use the default `painterSortStable` function.
         *
         * @param {?Function} method - The opaque sort function.
         */
        this.setOpaqueSort = function ( method ) {

            _opaqueSort = method;

        };

        /**
         * Sets a custom transparent sort function for the render lists. Pass `null`
         * to use the default `reversePainterSortStable` function.
         *
         * @param {?Function} method - The opaque sort function.
         */
        this.setTransparentSort = function ( method ) {

            _transparentSort = method;

        };

        // Clearing

        /**
         * Returns the clear color.
         *
         * @param {Color} target - The method writes the result in this target object.
         * @return {Color} The clear color.
         */
        this.getClearColor = function ( target ) {

            return target.copy( background.getClearColor() );

        };

        /**
         * Sets the clear color and alpha.
         *
         * @param {Color} color - The clear color.
         * @param {number} [alpha=1] - The clear alpha.
         */
        this.setClearColor = function () {

            background.setClearColor( ...arguments );

        };

        /**
         * Returns the clear alpha. Ranges within `[0,1]`.
         *
         * @return {number} The clear alpha.
         */
        this.getClearAlpha = function () {

            return background.getClearAlpha();

        };

        /**
         * Sets the clear alpha.
         *
         * @param {number} alpha - The clear alpha.
         */
        this.setClearAlpha = function () {

            background.setClearAlpha( ...arguments );

        };

        /**
         * Tells the renderer to clear its color, depth or stencil drawing buffer(s).
         * This method initializes the buffers to the current clear color values.
         *
         * @param {boolean} [color=true] - Whether the color buffer should be cleared or not.
         * @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not.
         * @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not.
         */
        this.clear = function ( color = true, depth = true, stencil = true ) {

            let bits = 0;

            if ( color ) {

                // check if we're trying to clear an integer target
                let isIntegerFormat = false;
                if ( _currentRenderTarget !== null ) {

                    const targetFormat = _currentRenderTarget.texture.format;
                    isIntegerFormat = targetFormat === RGBAIntegerFormat ||
                        targetFormat === RGIntegerFormat ||
                        targetFormat === RedIntegerFormat;

                }

                // use the appropriate clear functions to clear the target if it's a signed
                // or unsigned integer target
                if ( isIntegerFormat ) {

                    const targetType = _currentRenderTarget.texture.type;
                    const isUnsignedType = targetType === UnsignedByteType ||
                        targetType === UnsignedIntType ||
                        targetType === UnsignedShortType ||
                        targetType === UnsignedInt248Type ||
                        targetType === UnsignedShort4444Type ||
                        targetType === UnsignedShort5551Type;

                    const clearColor = background.getClearColor();
                    const a = background.getClearAlpha();
                    const r = clearColor.r;
                    const g = clearColor.g;
                    const b = clearColor.b;

                    if ( isUnsignedType ) {

                        uintClearColor[ 0 ] = r;
                        uintClearColor[ 1 ] = g;
                        uintClearColor[ 2 ] = b;
                        uintClearColor[ 3 ] = a;
                        _gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );

                    } else {

                        intClearColor[ 0 ] = r;
                        intClearColor[ 1 ] = g;
                        intClearColor[ 2 ] = b;
                        intClearColor[ 3 ] = a;
                        _gl.clearBufferiv( _gl.COLOR, 0, intClearColor );

                    }

                } else {

                    bits |= _gl.COLOR_BUFFER_BIT;

                }

            }

            if ( depth ) {

                bits |= _gl.DEPTH_BUFFER_BIT;

            }

            if ( stencil ) {

                bits |= _gl.STENCIL_BUFFER_BIT;
                this.state.buffers.stencil.setMask( 0xffffffff );

            }

            _gl.clear( bits );

        };

        /**
         * Clears the color buffer. Equivalent to calling `renderer.clear( true, false, false )`.
         */
        this.clearColor = function () {

            this.clear( true, false, false );

        };

        /**
         * Clears the depth buffer. Equivalent to calling `renderer.clear( false, true, false )`.
         */
        this.clearDepth = function () {

            this.clear( false, true, false );

        };

        /**
         * Clears the stencil buffer. Equivalent to calling `renderer.clear( false, false, true )`.
         */
        this.clearStencil = function () {

            this.clear( false, false, true );

        };

        /**
         * Frees the GPU-related resources allocated by this instance. Call this
         * method whenever this instance is no longer used in your app.
         */
        this.dispose = function () {

            canvas.removeEventListener( 'webglcontextlost', onContextLost, false );
            canvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );
            canvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );

            background.dispose();
            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 );

            animation.stop();

        };

        // Events

        function onContextLost( event ) {

            event.preventDefault();

            console.log( 'THREE.WebGLRenderer: Context Lost.' );

            _isContextLost = true;

        }

        function onContextRestore( /* event */ ) {

            console.log( 'THREE.WebGLRenderer: Context Restored.' );

            _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;

        }

        function onContextCreationError( event ) {

            console.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );

        }

        function onMaterialDispose( event ) {

            const material = event.target;

            material.removeEventListener( 'dispose', onMaterialDispose );

            deallocateMaterial( material );

        }

        // Buffer deallocation

        function deallocateMaterial( material ) {

            releaseMaterialProgramReferences( material );

            properties.remove( material );

        }


        function releaseMaterialProgramReferences( material ) {

            const programs = properties.get( material ).programs;

            if ( programs !== undefined ) {

                programs.forEach( function ( program ) {

                    programCache.releaseProgram( program );

                } );

                if ( material.isShaderMaterial ) {

                    programCache.releaseShaderCache( material );

                }

            }

        }

        // Buffer rendering

        this.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {

            if ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)

            const frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );

            const program = setProgram( camera, scene, geometry, material, object );

            state.setMaterial( material, frontFaceCW );

            //

            let index = geometry.index;
            let rangeFactor = 1;

            if ( material.wireframe === true ) {

                index = geometries.getWireframeAttribute( geometry );

                if ( index === undefined ) return;

                rangeFactor = 2;

            }

            //

            const drawRange = geometry.drawRange;
            const position = geometry.attributes.position;

            let drawStart = drawRange.start * rangeFactor;
            let drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;

            if ( group !== null ) {

                drawStart = Math.max( drawStart, group.start * rangeFactor );
                drawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );

            }

            if ( index !== null ) {

                drawStart = Math.max( drawStart, 0 );
                drawEnd = Math.min( drawEnd, index.count );

            } else if ( position !== undefined && position !== null ) {

                drawStart = Math.max( drawStart, 0 );
                drawEnd = Math.min( drawEnd, position.count );

            }

            const drawCount = drawEnd - drawStart;

            if ( drawCount < 0 || drawCount === Infinity ) return;

            //

            bindingStates.setup( object, material, program, geometry, index );

            let attribute;
            let renderer = bufferRenderer;

            if ( index !== null ) {

                attribute = attributes.get( index );

                renderer = indexedBufferRenderer;
                renderer.setIndex( attribute );

            }

            //

            if ( object.isMesh ) {

                if ( material.wireframe === true ) {

                    state.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );
                    renderer.setMode( _gl.LINES );

                } else {

                    renderer.setMode( _gl.TRIANGLES );

                }

            } else if ( object.isLine ) {

                let lineWidth = material.linewidth;

                if ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material

                state.setLineWidth( lineWidth * getTargetPixelRatio() );

                if ( object.isLineSegments ) {

                    renderer.setMode( _gl.LINES );

                } else if ( object.isLineLoop ) {

                    renderer.setMode( _gl.LINE_LOOP );

                } else {

                    renderer.setMode( _gl.LINE_STRIP );

                }

            } else if ( object.isPoints ) {

                renderer.setMode( _gl.POINTS );

            } else if ( object.isSprite ) {

                renderer.setMode( _gl.TRIANGLES );

            }

            if ( object.isBatchedMesh ) {

                if ( object._multiDrawInstances !== null ) {

                    // @deprecated, r174
                    warnOnce( 'THREE.WebGLRenderer: renderMultiDrawInstances has been deprecated and will be removed in r184. Append to renderMultiDraw arguments and use indirection.' );
                    renderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );

                } else {

                    if ( ! extensions.get( 'WEBGL_multi_draw' ) ) {

                        const starts = object._multiDrawStarts;
                        const counts = object._multiDrawCounts;
                        const drawCount = object._multiDrawCount;
                        const bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;
                        const uniforms = properties.get( material ).currentProgram.getUniforms();
                        for ( let i = 0; i < drawCount; i ++ ) {

                            uniforms.setValue( _gl, '_gl_DrawID', i );
                            renderer.render( starts[ i ] / bytesPerElement, counts[ i ] );

                        }

                    } else {

                        renderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );

                    }

                }

            } else if ( object.isInstancedMesh ) {

                renderer.renderInstances( drawStart, drawCount, object.count );

            } else if ( geometry.isInstancedBufferGeometry ) {

                const maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;
                const instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );

                renderer.renderInstances( drawStart, drawCount, instanceCount );

            } else {

                renderer.render( drawStart, drawCount );

            }

        };

        // Compile

        function prepareMaterial( material, scene, object ) {

            if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {

                material.side = BackSide;
                material.needsUpdate = true;
                getProgram( material, scene, object );

                material.side = FrontSide;
                material.needsUpdate = true;
                getProgram( material, scene, object );

                material.side = DoubleSide;

            } else {

                getProgram( material, scene, object );

            }

        }

        /**
         * Compiles all materials in the scene with the camera. This is useful to precompile shaders
         * before the first rendering. If you want to add a 3D object to an existing scene, use the third
         * optional parameter for applying the target scene.
         *
         * Note that the (target) scene's lighting and environment must be configured before calling this method.
         *
         * @param {Object3D} scene - The scene or another type of 3D object to precompile.
         * @param {Camera} camera - The camera.
         * @param {?Scene} [targetScene=null] - The target scene.
         * @return {Set<Material>} The precompiled materials.
         */
        this.compile = function ( scene, camera, targetScene = null ) {

            if ( targetScene === null ) targetScene = scene;

            currentRenderState = renderStates.get( targetScene );
            currentRenderState.init( camera );

            renderStateStack.push( currentRenderState );

            // gather lights from both the target scene and the new object that will be added to the scene.

            targetScene.traverseVisible( function ( object ) {

                if ( object.isLight && object.layers.test( camera.layers ) ) {

                    currentRenderState.pushLight( object );

                    if ( object.castShadow ) {

                        currentRenderState.pushShadow( object );

                    }

                }

            } );

            if ( scene !== targetScene ) {

                scene.traverseVisible( function ( object ) {

                    if ( object.isLight && object.layers.test( camera.layers ) ) {

                        currentRenderState.pushLight( object );

                        if ( object.castShadow ) {

                            currentRenderState.pushShadow( object );

                        }

                    }

                } );

            }

            currentRenderState.setupLights();

            // Only initialize materials in the new scene, not the targetScene.

            const materials = new Set();

            scene.traverse( function ( object ) {

                if ( ! ( object.isMesh || object.isPoints || object.isLine || object.isSprite ) ) {

                    return;

                }

                const material = object.material;

                if ( material ) {

                    if ( Array.isArray( material ) ) {

                        for ( let i = 0; i < material.length; i ++ ) {

                            const material2 = material[ i ];

                            prepareMaterial( material2, targetScene, object );
                            materials.add( material2 );

                        }

                    } else {

                        prepareMaterial( material, targetScene, object );
                        materials.add( material );

                    }

                }

            } );

            currentRenderState = renderStateStack.pop();

            return materials;

        };

        // compileAsync

        /**
         * Asynchronous version of {@link WebGLRenderer#compile}.
         *
         * This method makes use of the `KHR_parallel_shader_compile` WebGL extension. Hence,
         * it is recommended to use this version of `compile()` whenever possible.
         *
         * @async
         * @param {Object3D} scene - The scene or another type of 3D object to precompile.
         * @param {Camera} camera - The camera.
         * @param {?Scene} [targetScene=null] - The target scene.
         * @return {Promise} A Promise that resolves when the given scene can be rendered without unnecessary stalling due to shader compilation.
         */
        this.compileAsync = function ( scene, camera, targetScene = null ) {

            const materials = this.compile( scene, camera, targetScene );

            // 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 ) => {

                function checkMaterialsReady() {

                    materials.forEach( function ( material ) {

                        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 );

                        }

                    } );

                    // once the list of compiling materials is empty, call the callback

                    if ( materials.size === 0 ) {

                        resolve( scene );
                        return;

                    }

                    // if some materials are still not ready, wait a bit and check again

                    setTimeout( checkMaterialsReady, 10 );

                }

                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.

                    checkMaterialsReady();

                } else {

                    // Otherwise start by waiting a bit to give the materials we just
                    // initialized a chance to finish.

                    setTimeout( checkMaterialsReady, 10 );

                }

            } );

        };

        // Animation Loop

        let onAnimationFrameCallback = null;

        function onAnimationFrame( time ) {

            if ( onAnimationFrameCallback ) onAnimationFrameCallback( time );

        }

        function onXRSessionStart() {

            animation.stop();

        }

        function onXRSessionEnd() {

            animation.start();

        }

        const animation = new WebGLAnimation();
        animation.setAnimationLoop( onAnimationFrame );

        if ( typeof self !== 'undefined' ) animation.setContext( self );

        this.setAnimationLoop = function ( callback ) {

            onAnimationFrameCallback = callback;
            xr.setAnimationLoop( callback );

            ( callback === null ) ? animation.stop() : animation.start();

        };

        xr.addEventListener( 'sessionstart', onXRSessionStart );
        xr.addEventListener( 'sessionend', onXRSessionEnd );

        // Rendering

        /**
         * Renders the given scene (or other type of 3D object) using the given camera.
         *
         * The render is done to a previously specified render target set by calling {@link WebGLRenderer#setRenderTarget}
         * or to the canvas as usual.
         *
         * By default render buffers are cleared before rendering but you can prevent
         * this by setting the property `autoClear` to `false`. If you want to prevent
         * only certain buffers being cleared you can `autoClearColor`, `autoClearDepth`
         * or `autoClearStencil` to `false`. To force a clear, use {@link WebGLRenderer#clear}.
         *
         * @param {Object3D} scene - The scene to render.
         * @param {Camera} camera - The camera.
         */
        this.render = function ( scene, camera ) {

            if ( camera !== undefined && camera.isCamera !== true ) {

                console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );
                return;

            }

            if ( _isContextLost === true ) return;

            // update scene graph

            if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();

            // update camera matrices and frustum

            if ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();

            if ( xr.enabled === true && xr.isPresenting === true ) {

                if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );

                camera = xr.getCamera(); // use XR camera for rendering

            }

            //
            if ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );

            currentRenderState = renderStates.get( scene, renderStateStack.length );
            currentRenderState.init( camera );

            renderStateStack.push( currentRenderState );

            _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );
            _frustum.setFromProjectionMatrix( _projScreenMatrix, WebGLCoordinateSystem, camera.reversedDepth );

            _localClippingEnabled = this.localClippingEnabled;
            _clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );

            currentRenderList = renderLists.get( scene, renderListStack.length );
            currentRenderList.init();

            renderListStack.push( currentRenderList );

            if ( xr.enabled === true && xr.isPresenting === true ) {

                const depthSensingMesh = _this.xr.getDepthSensingMesh();

                if ( depthSensingMesh !== null ) {

                    projectObject( depthSensingMesh, camera, - Infinity, _this.sortObjects );

                }

            }

            projectObject( scene, camera, 0, _this.sortObjects );

            currentRenderList.finish();

            if ( _this.sortObjects === true ) {

                currentRenderList.sort( _opaqueSort, _transparentSort );

            }

            _renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false;
            if ( _renderBackground ) {

                background.addToRenderList( currentRenderList, scene );

            }

            //

            this.info.render.frame ++;

            if ( _clippingEnabled === true ) clipping.beginShadows();

            const shadowsArray = currentRenderState.state.shadowsArray;

            shadowMap.render( shadowsArray, scene, camera );

            if ( _clippingEnabled === true ) clipping.endShadows();

            //

            if ( this.info.autoReset === true ) this.info.reset();

            // render scene

            const opaqueObjects = currentRenderList.opaque;
            const transmissiveObjects = currentRenderList.transmissive;

            currentRenderState.setupLights();

            if ( camera.isArrayCamera ) {

                const cameras = camera.cameras;

                if ( transmissiveObjects.length > 0 ) {

                    for ( let i = 0, l = cameras.length; i < l; i ++ ) {

                        const camera2 = cameras[ i ];

                        renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera2 );

                    }

                }

                if ( _renderBackground ) background.render( scene );

                for ( let i = 0, l = cameras.length; i < l; i ++ ) {

                    const camera2 = cameras[ i ];

                    renderScene( currentRenderList, scene, camera2, camera2.viewport );

                }

            } else {

                if ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );

                if ( _renderBackground ) background.render( scene );

                renderScene( currentRenderList, scene, camera );

            }

            //

            if ( _currentRenderTarget !== null && _currentActiveMipmapLevel === 0 ) {

                // resolve multisample renderbuffers to a single-sample texture if necessary

                textures.updateMultisampleRenderTarget( _currentRenderTarget );

                // Generate mipmap if we're using any kind of mipmap filtering

                textures.updateRenderTargetMipmap( _currentRenderTarget );

            }

            //

            if ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );

            // _gl.finish();

            bindingStates.resetDefaultState();
            _currentMaterialId = -1;
            _currentCamera = null;

            renderStateStack.pop();

            if ( renderStateStack.length > 0 ) {

                currentRenderState = renderStateStack[ renderStateStack.length - 1 ];

                if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, currentRenderState.state.camera );

            } else {

                currentRenderState = null;

            }

            renderListStack.pop();

            if ( renderListStack.length > 0 ) {

                currentRenderList = renderListStack[ renderListStack.length - 1 ];

            } else {

                currentRenderList = null;

            }

        };

        function projectObject( object, camera, groupOrder, sortObjects ) {

            if ( object.visible === false ) return;

            const visible = object.layers.test( camera.layers );

            if ( visible ) {

                if ( object.isGroup ) {

                    groupOrder = object.renderOrder;

                } else if ( object.isLOD ) {

                    if ( object.autoUpdate === true ) object.update( camera );

                } else if ( object.isLight ) {

                    currentRenderState.pushLight( object );

                    if ( object.castShadow ) {

                        currentRenderState.pushShadow( object );

                    }

                } else if ( object.isSprite ) {

                    if ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {

                        if ( sortObjects ) {

                            _vector4.setFromMatrixPosition( object.matrixWorld )
                                .applyMatrix4( _projScreenMatrix );

                        }

                        const geometry = objects.update( object );
                        const material = object.material;

                        if ( material.visible ) {

                            currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );

                        }

                    }

                } else if ( object.isMesh || object.isLine || object.isPoints ) {

                    if ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {

                        const geometry = objects.update( object );
                        const material = object.material;

                        if ( sortObjects ) {

                            if ( object.boundingSphere !== undefined ) {

                                if ( object.boundingSphere === null ) object.computeBoundingSphere();
                                _vector4.copy( object.boundingSphere.center );

                            } else {

                                if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();
                                _vector4.copy( geometry.boundingSphere.center );

                            }

                            _vector4
                                .applyMatrix4( object.matrixWorld )
                                .applyMatrix4( _projScreenMatrix );

                        }

                        if ( Array.isArray( material ) ) {

                            const groups = geometry.groups;

                            for ( let i = 0, l = groups.length; i < l; i ++ ) {

                                const group = groups[ i ];
                                const groupMaterial = material[ group.materialIndex ];

                                if ( groupMaterial && groupMaterial.visible ) {

                                    currentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group );

                                }

                            }

                        } else if ( material.visible ) {

                            currentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );

                        }

                    }

                }

            }

            const children = object.children;

            for ( let i = 0, l = children.length; i < l; i ++ ) {

                projectObject( children[ i ], camera, groupOrder, sortObjects );

            }

        }

        function renderScene( currentRenderList, scene, camera, viewport ) {

            const opaqueObjects = currentRenderList.opaque;
            const transmissiveObjects = currentRenderList.transmissive;
            const transparentObjects = currentRenderList.transparent;

            currentRenderState.setupLightsView( camera );

            if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );

            if ( viewport ) state.viewport( _currentViewport.copy( viewport ) );

            if ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );
            if ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );
            if ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );

            // 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 );

            state.setPolygonOffset( false );

        }

        function renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {

            const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;

            if ( overrideMaterial !== null ) {

                return;

            }

            if ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) {

                currentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, {
                    generateMipmaps: true,
                    type: ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ) ? HalfFloatType : UnsignedByteType,
                    minFilter: LinearMipmapLinearFilter,
                    samples: 4,
                    stencilBuffer: stencil,
                    resolveDepthBuffer: false,
                    resolveStencilBuffer: false,
                    colorSpace: ColorManagement.workingColorSpace,
                } );

                // debug

                /*
                const geometry = new PlaneGeometry();
                const material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );

                const mesh = new Mesh( geometry, material );
                scene.add( mesh );
                */

            }

            const transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ];

            const activeViewport = camera.viewport || _currentViewport;
            transmissionRenderTarget.setSize( activeViewport.z * _this.transmissionResolutionScale, activeViewport.w * _this.transmissionResolutionScale );

            //

            const currentRenderTarget = _this.getRenderTarget();
            const currentActiveCubeFace = _this.getActiveCubeFace();
            const currentActiveMipmapLevel = _this.getActiveMipmapLevel();

            _this.setRenderTarget( transmissionRenderTarget );

            _this.getClearColor( _currentClearColor );
            _currentClearAlpha = _this.getClearAlpha();
            if ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );

            _this.clear();

            if ( _renderBackground ) background.render( scene );

            // 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;

            // Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector).
            // Transmission render pass requires viewport to match the transmissionRenderTarget.
            const currentCameraViewport = camera.viewport;
            if ( camera.viewport !== undefined ) camera.viewport = undefined;

            currentRenderState.setupLightsView( camera );

            if ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );

            renderObjects( opaqueObjects, scene, camera );

            textures.updateMultisampleRenderTarget( transmissionRenderTarget );
            textures.updateRenderTargetMipmap( transmissionRenderTarget );

            if ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131

                let renderTargetNeedsUpdate = false;

                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;

                    if ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {

                        const currentSide = material.side;

                        material.side = BackSide;
                        material.needsUpdate = true;

                        renderObject( object, scene, camera, geometry, material, group );

                        material.side = currentSide;
                        material.needsUpdate = true;

                        renderTargetNeedsUpdate = true;

                    }

                }

                if ( renderTargetNeedsUpdate === true ) {

                    textures.updateMultisampleRenderTarget( transmissionRenderTarget );
                    textures.updateRenderTargetMipmap( transmissionRenderTarget );

                }

            }

            _this.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );

            _this.setClearColor( _currentClearColor, _currentClearAlpha );

            if ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport;

            _this.toneMapping = currentToneMapping;

        }

        function renderObjects( renderList, scene, camera ) {

            const overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;

            for ( let i = 0, l = renderList.length; i < l; i ++ ) {

                const renderItem = renderList[ i ];

                const object = renderItem.object;
                const geometry = renderItem.geometry;
                const group = renderItem.group;
                let material = renderItem.material;

                if ( material.allowOverride === true && overrideMaterial !== null ) {

                    material = overrideMaterial;

                }

                if ( object.layers.test( camera.layers ) ) {

                    renderObject( object, scene, camera, geometry, material, group );

                }

            }

        }

        function renderObject( object, scene, camera, geometry, material, group ) {

            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 );

            if ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {

                material.side = BackSide;
                material.needsUpdate = true;
                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

                material.side = FrontSide;
                material.needsUpdate = true;
                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

                material.side = DoubleSide;

            } else {

                _this.renderBufferDirect( camera, scene, geometry, material, object, group );

            }

            object.onAfterRender( _this, scene, camera, geometry, material, group );

        }

        function getProgram( material, scene, object ) {

            if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...

            const materialProperties = properties.get( material );

            const lights = currentRenderState.state.lights;
            const shadowsArray = currentRenderState.state.shadowsArray;

            const lightsStateVersion = lights.state.version;

            const parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );
            const programCacheKey = programCache.getProgramCacheKey( parameters );

            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

            materialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;
            materialProperties.fog = scene.fog;
            materialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );
            materialProperties.envMapRotation = ( materialProperties.environment !== null && material.envMap === null ) ? scene.environmentRotation : material.envMapRotation;

            if ( programs === undefined ) {

                // new material

                material.addEventListener( 'dispose', onMaterialDispose );

                programs = new Map();
                materialProperties.programs = programs;

            }

            let program = programs.get( programCacheKey );

            if ( program !== undefined ) {

                // early out if program and light state is identical

                if ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {

                    updateCommonMaterialProperties( material, parameters );

                    return program;

                }

            } else {

                parameters.uniforms = programCache.getUniforms( material );

                material.onBeforeCompile( parameters, _this );

                program = programCache.acquireProgram( parameters, programCacheKey );
                programs.set( programCacheKey, program );

                materialProperties.uniforms = parameters.uniforms;

            }

            const uniforms = materialProperties.uniforms;

            if ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {

                uniforms.clippingPlanes = clipping.uniform;

            }

            updateCommonMaterialProperties( material, parameters );

            // store the light setup it was created for

            materialProperties.needsLights = materialNeedsLights( material );
            materialProperties.lightsStateVersion = lightsStateVersion;

            if ( materialProperties.needsLights ) {

                // wire up the material to this renderer's lighting state

                uniforms.ambientLightColor.value = lights.state.ambient;
                uniforms.lightProbe.value = lights.state.probe;
                uniforms.directionalLights.value = lights.state.directional;
                uniforms.directionalLightShadows.value = lights.state.directionalShadow;
                uniforms.spotLights.value = lights.state.spot;
                uniforms.spotLightShadows.value = lights.state.spotShadow;
                uniforms.rectAreaLights.value = lights.state.rectArea;
                uniforms.ltc_1.value = lights.state.rectAreaLTC1;
                uniforms.ltc_2.value = lights.state.rectAreaLTC2;
                uniforms.pointLights.value = lights.state.point;
                uniforms.pointLightShadows.value = lights.state.pointShadow;
                uniforms.hemisphereLights.value = lights.state.hemi;

                uniforms.directionalShadowMap.value = lights.state.directionalShadowMap;
                uniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;
                uniforms.spotShadowMap.value = lights.state.spotShadowMap;
                uniforms.spotLightMatrix.value = lights.state.spotLightMatrix;
                uniforms.spotLightMap.value = lights.state.spotLightMap;
                uniforms.pointShadowMap.value = lights.state.pointShadowMap;
                uniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;
                // TODO (abelnation): add area lights shadow info to uniforms

            }

            materialProperties.currentProgram = program;
            materialProperties.uniformsList = null;

            return program;

        }

        function getUniformList( materialProperties ) {

            if ( materialProperties.uniformsList === null ) {

                const progUniforms = materialProperties.currentProgram.getUniforms();
                materialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );

            }

            return materialProperties.uniformsList;

        }

        function updateCommonMaterialProperties( material, parameters ) {

            const materialProperties = properties.get( material );

            materialProperties.outputColorSpace = parameters.outputColorSpace;
            materialProperties.batching = parameters.batching;
            materialProperties.batchingColor = parameters.batchingColor;
            materialProperties.instancing = parameters.instancing;
            materialProperties.instancingColor = parameters.instancingColor;
            materialProperties.instancingMorph = parameters.instancingMorph;
            materialProperties.skinning = parameters.skinning;
            materialProperties.morphTargets = parameters.morphTargets;
            materialProperties.morphNormals = parameters.morphNormals;
            materialProperties.morphColors = parameters.morphColors;
            materialProperties.morphTargetsCount = parameters.morphTargetsCount;
            materialProperties.numClippingPlanes = parameters.numClippingPlanes;
            materialProperties.numIntersection = parameters.numClipIntersection;
            materialProperties.vertexAlphas = parameters.vertexAlphas;
            materialProperties.vertexTangents = parameters.vertexTangents;
            materialProperties.toneMapping = parameters.toneMapping;

        }

        function setProgram( camera, scene, geometry, material, object ) {

            if ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...

            textures.resetTextureUnits();

            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;

            let toneMapping = NoToneMapping;

            if ( material.toneMapped ) {

                if ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {

                    toneMapping = _this.toneMapping;

                }

            }

            const morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;
            const morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;

            const materialProperties = properties.get( material );
            const lights = currentRenderState.state.lights;

            if ( _clippingEnabled === true ) {

                if ( _localClippingEnabled === true || camera !== _currentCamera ) {

                    const useCache =
                        camera === _currentCamera &&
                        material.id === _currentMaterialId;

                    // 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 );

                }

            }

            //

            let needsProgramChange = false;

            if ( material.version === materialProperties.__version ) {

                if ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {

                    needsProgramChange = true;

                } else if ( materialProperties.outputColorSpace !== colorSpace ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batching === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batchingColor === true && object.colorTexture === null ) {

                    needsProgramChange = true;

                } else if ( object.isBatchedMesh && materialProperties.batchingColor === false && object.colorTexture !== null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancing === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {

                    needsProgramChange = true;

                } else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {

                    needsProgramChange = true;

                } else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null ) {

                    needsProgramChange = true;

                } else if ( object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null ) {

                    needsProgramChange = true;

                } else if ( materialProperties.envMap !== envMap ) {

                    needsProgramChange = true;

                } else if ( material.fog === true && materialProperties.fog !== fog ) {

                    needsProgramChange = true;

                } else if ( materialProperties.numClippingPlanes !== undefined &&
                    ( materialProperties.numClippingPlanes !== clipping.numPlanes ||
                    materialProperties.numIntersection !== clipping.numIntersection ) ) {

                    needsProgramChange = true;

                } else if ( materialProperties.vertexAlphas !== vertexAlphas ) {

                    needsProgramChange = true;

                } else if ( materialProperties.vertexTangents !== vertexTangents ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphTargets !== morphTargets ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphNormals !== morphNormals ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphColors !== morphColors ) {

                    needsProgramChange = true;

                } else if ( materialProperties.toneMapping !== toneMapping ) {

                    needsProgramChange = true;

                } else if ( materialProperties.morphTargetsCount !== morphTargetsCount ) {

                    needsProgramChange = true;

                }

            } else {

                needsProgramChange = true;
                materialProperties.__version = material.version;

            }

            //

            let program = materialProperties.currentProgram;

            if ( needsProgramChange === true ) {

                program = getProgram( material, scene, object );

            }

            let refreshProgram = false;
            let refreshMaterial = false;
            let refreshLights = false;

            const p_uniforms = program.getUniforms(),
                m_uniforms = materialProperties.uniforms;

            if ( state.useProgram( program.program ) ) {

                refreshProgram = true;
                refreshMaterial = true;
                refreshLights = true;

            }

            if ( material.id !== _currentMaterialId ) {

                _currentMaterialId = material.id;

                refreshMaterial = true;

            }

            if ( refreshProgram || _currentCamera !== camera ) {

                // common camera uniforms

                const reversedDepthBuffer = state.buffers.depth.getReversed();

                if ( reversedDepthBuffer && camera.reversedDepth !== true ) {

                    camera._reversedDepth = true;
                    camera.updateProjectionMatrix();

                }

                p_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );

                p_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );

                const uCamPos = p_uniforms.map.cameraPosition;

                if ( uCamPos !== undefined ) {

                    uCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );

                }

                if ( capabilities.logarithmicDepthBuffer ) {

                    p_uniforms.setValue( _gl, 'logDepthBufFC',
                        2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );

                }

                // consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067

                if ( material.isMeshPhongMaterial ||
                    material.isMeshToonMaterial ||
                    material.isMeshLambertMaterial ||
                    material.isMeshBasicMaterial ||
                    material.isMeshStandardMaterial ||
                    material.isShaderMaterial ) {

                    p_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );

                }

                if ( _currentCamera !== camera ) {

                    _currentCamera = camera;

                    // 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

                }

            }

            // 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 ) {

                p_uniforms.setOptional( _gl, object, 'bindMatrix' );
                p_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );

                const skeleton = object.skeleton;

                if ( skeleton ) {

                    if ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();

                    p_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );

                }

            }

            if ( object.isBatchedMesh ) {

                p_uniforms.setOptional( _gl, object, 'batchingTexture' );
                p_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );

                p_uniforms.setOptional( _gl, object, 'batchingIdTexture' );
                p_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures );

                p_uniforms.setOptional( _gl, object, 'batchingColorTexture' );
                if ( object._colorsTexture !== null ) {

                    p_uniforms.setValue( _gl, 'batchingColorTexture', object._colorsTexture, textures );

                }

            }

            const morphAttributes = geometry.morphAttributes;

            if ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined ) ) {

                morphtargets.update( object, geometry, program );

            }

            if ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {

                materialProperties.receiveShadow = object.receiveShadow;
                p_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );

            }

            // https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512

            if ( material.isMeshGouraudMaterial && material.envMap !== null ) {

                m_uniforms.envMap.value = envMap;

                m_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? -1 : 1;

            }

            if ( material.isMeshStandardMaterial && material.envMap === null && scene.environment !== null ) {

                m_uniforms.envMapIntensity.value = scene.environmentIntensity;

            }

            if ( refreshMaterial ) {

                p_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );

                if ( materialProperties.needsLights ) {

                    // the current material requires lighting info

                    // 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

                if ( fog && material.fog === true ) {

                    materials.refreshFogUniforms( m_uniforms, fog );

                }

                materials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] );

                WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );

            }

            if ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {

                WebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );
                material.uniformsNeedUpdate = false;

            }

            if ( material.isSpriteMaterial ) {

                p_uniforms.setValue( _gl, 'center', object.center );

            }

            // common matrices

            p_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );
            p_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );
            p_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );

            // UBOs

            if ( material.isShaderMaterial || material.isRawShaderMaterial ) {

                const groups = material.uniformsGroups;

                for ( let i = 0, l = groups.length; i < l; i ++ ) {

                    const group = groups[ i ];

                    uniformsGroups.update( group, program );
                    uniformsGroups.bind( group, program );

                }

            }

            return program;

        }

        // If uniforms are marked as clean, they don't need to be loaded to the GPU.

        function markUniformsLightsNeedsUpdate( uniforms, value ) {

            uniforms.ambientLightColor.needsUpdate = value;
            uniforms.lightProbe.needsUpdate = value;

            uniforms.directionalLights.needsUpdate = value;
            uniforms.directionalLightShadows.needsUpdate = value;
            uniforms.pointLights.needsUpdate = value;
            uniforms.pointLightShadows.needsUpdate = value;
            uniforms.spotLights.needsUpdate = value;
            uniforms.spotLightShadows.needsUpdate = value;
            uniforms.rectAreaLights.needsUpdate = value;
            uniforms.hemisphereLights.needsUpdate = value;

        }

        function materialNeedsLights( material ) {

            return material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||
                material.isMeshStandardMaterial || material.isShadowMaterial ||
                ( material.isShaderMaterial && material.lights === true );

        }

        /**
         * Returns the active cube face.
         *
         * @return {number} The active cube face.
         */
        this.getActiveCubeFace = function () {

            return _currentActiveCubeFace;

        };

        /**
         * Returns the active mipmap level.
         *
         * @return {number} The active mipmap level.
         */
        this.getActiveMipmapLevel = function () {

            return _currentActiveMipmapLevel;

        };

        /**
         * Returns the active render target.
         *
         * @return {?WebGLRenderTarget} The active render target. Returns `null` if no render target
         * is currently set.
         */
        this.getRenderTarget = function () {

            return _currentRenderTarget;

        };

        this.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {

            const renderTargetProperties = properties.get( renderTarget );

            renderTargetProperties.__autoAllocateDepthBuffer = renderTarget.resolveDepthBuffer === false;
            if ( renderTargetProperties.__autoAllocateDepthBuffer === false ) {

                // 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.
                renderTargetProperties.__useRenderToTexture = false;

            }

            properties.get( renderTarget.texture ).__webglTexture = colorTexture;
            properties.get( renderTarget.depthTexture ).__webglTexture = renderTargetProperties.__autoAllocateDepthBuffer ? undefined : depthTexture;

            renderTargetProperties.__hasExternalTextures = true;

        };

        this.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {

            const renderTargetProperties = properties.get( renderTarget );
            renderTargetProperties.__webglFramebuffer = defaultFramebuffer;
            renderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;

        };

        const _scratchFrameBuffer = _gl.createFramebuffer();

        /**
         * Sets the active rendertarget.
         *
         * @param {?WebGLRenderTarget} renderTarget - The render target to set. When `null` is given,
         * the canvas is set as the active render target instead.
         * @param {number} [activeCubeFace=0] - The active cube face when using a cube render target.
         * Indicates the z layer to render in to when using 3D or array render targets.
         * @param {number} [activeMipmapLevel=0] - The active mipmap level.
         */
        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;

            if ( renderTarget ) {

                const renderTargetProperties = properties.get( renderTarget );

                if ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {

                    // We need to make sure to rebind the framebuffer.
                    state.bindFramebuffer( _gl.FRAMEBUFFER, null );
                    useDefaultFramebuffer = false;

                } else if ( renderTargetProperties.__webglFramebuffer === undefined ) {

                    textures.setupRenderTarget( renderTarget );

                } 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 );

                } else if ( renderTarget.depthBuffer ) {

                    // check if the depth texture is already bound to the frame buffer and that it's been initialized
                    const depthTexture = renderTarget.depthTexture;
                    if ( renderTargetProperties.__boundDepthTexture !== depthTexture ) {

                        // check if the depth texture is compatible
                        if (
                            depthTexture !== null &&
                            properties.has( depthTexture ) &&
                            ( renderTarget.width !== depthTexture.image.width || renderTarget.height !== depthTexture.image.height )
                        ) {

                            throw new Error( 'WebGLRenderTarget: Attached DepthTexture is initialized to the incorrect size.' );

                        }

                        // Swap the depth buffer to the currently attached one
                        textures.setupDepthRenderbuffer( renderTarget );

                    }

                }

                const texture = renderTarget.texture;

                if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {

                    isRenderTarget3D = true;

                }

                const __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;

                if ( renderTarget.isWebGLCubeRenderTarget ) {

                    if ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {

                        framebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];

                    } else {

                        framebuffer = __webglFramebuffer[ activeCubeFace ];

                    }

                    isCube = true;

                } else if ( ( renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {

                    framebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;

                } else {

                    if ( Array.isArray( __webglFramebuffer ) ) {

                        framebuffer = __webglFramebuffer[ activeMipmapLevel ];

                    } else {

                        framebuffer = __webglFramebuffer;

                    }

                }

                _currentViewport.copy( renderTarget.viewport );
                _currentScissor.copy( renderTarget.scissor );
                _currentScissorTest = renderTarget.scissorTest;

            } else {

                _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();
                _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();
                _currentScissorTest = _scissorTest;

            }

            // Use a scratch frame buffer if rendering to a mip level to avoid depth buffers
            // being bound that are different sizes.
            if ( activeMipmapLevel !== 0 ) {

                framebuffer = _scratchFrameBuffer;

            }

            const framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

            if ( framebufferBound && useDefaultFramebuffer ) {

                state.drawBuffers( renderTarget, framebuffer );

            }

            state.viewport( _currentViewport );
            state.scissor( _currentScissor );
            state.setScissorTest( _currentScissorTest );

            if ( isCube ) {

                const textureProperties = properties.get( renderTarget.texture );
                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );

            } else if ( isRenderTarget3D ) {

                const layer = activeCubeFace;

                for ( let i = 0; i < renderTarget.textures.length; i ++ ) {

                    const textureProperties = properties.get( renderTarget.textures[ i ] );

                    _gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, textureProperties.__webglTexture, activeMipmapLevel, layer );

                }

            } else if ( renderTarget !== null && activeMipmapLevel !== 0 ) {

                // Only bind the frame buffer if we are using a scratch frame buffer to render to a mipmap.
                // If we rebind the texture when using a multi sample buffer then an error about inconsistent samples will be thrown.
                const textureProperties = properties.get( renderTarget.texture );
                _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, textureProperties.__webglTexture, activeMipmapLevel );

            }

            _currentMaterialId = -1; // reset current material to ensure correct uniform bindings

        };

        /**
         * Reads the pixel data from the given render target into the given buffer.
         *
         * @param {WebGLRenderTarget} renderTarget - The render target to read from.
         * @param {number} x - The `x` coordinate of the copy region's origin.
         * @param {number} y - The `y` coordinate of the copy region's origin.
         * @param {number} width - The width of the copy region.
         * @param {number} height - The height of the copy region.
         * @param {TypedArray} buffer - The result buffer.
         * @param {number} [activeCubeFaceIndex] - The active cube face index.
         * @param {number} [textureIndex=0] - The texture index of an MRT render target.
         */
        this.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, textureIndex = 0 ) {

            if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {

                console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );
                return;

            }

            let framebuffer = properties.get( renderTarget ).__webglFramebuffer;

            if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {

                framebuffer = framebuffer[ activeCubeFaceIndex ];

            }

            if ( framebuffer ) {

                state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

                try {

                    const texture = renderTarget.textures[ textureIndex ];
                    const textureFormat = texture.format;
                    const textureType = texture.type;

                    if ( ! capabilities.textureFormatReadable( textureFormat ) ) {

                        console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );
                        return;

                    }

                    if ( ! capabilities.textureTypeReadable( textureType ) ) {

                        console.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );
                        return;

                    }

                    // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)

                    if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {

                        // when using MRT, select the correct color buffer for the subsequent read command

                        if ( renderTarget.textures.length > 1 ) _gl.readBuffer( _gl.COLOR_ATTACHMENT0 + textureIndex );

                        _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );

                    }

                } finally {

                    // restore framebuffer of current render target if necessary

                    const framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
                    state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

                }

            }

        };

        /**
         * Asynchronous, non-blocking version of {@link WebGLRenderer#readRenderTargetPixels}.
         *
         * It is recommended to use this version of `readRenderTargetPixels()` whenever possible.
         *
         * @async
         * @param {WebGLRenderTarget} renderTarget - The render target to read from.
         * @param {number} x - The `x` coordinate of the copy region's origin.
         * @param {number} y - The `y` coordinate of the copy region's origin.
         * @param {number} width - The width of the copy region.
         * @param {number} height - The height of the copy region.
         * @param {TypedArray} buffer - The result buffer.
         * @param {number} [activeCubeFaceIndex] - The active cube face index.
         * @param {number} [textureIndex=0] - The texture index of an MRT render target.
         * @return {Promise<TypedArray>} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array.
         */
        this.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex, textureIndex = 0 ) {

            if ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {

                throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );

            }

            let framebuffer = properties.get( renderTarget ).__webglFramebuffer;
            if ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {

                framebuffer = framebuffer[ activeCubeFaceIndex ];

            }

            if ( framebuffer ) {

                // the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)
                if ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {

                    // set the active frame buffer to the one we want to read
                    state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );

                    const texture = renderTarget.textures[ textureIndex ];
                    const textureFormat = texture.format;
                    const textureType = texture.type;

                    if ( ! capabilities.textureFormatReadable( textureFormat ) ) {

                        throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );

                    }

                    if ( ! capabilities.textureTypeReadable( textureType ) ) {

                        throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );

                    }

                    const glBuffer = _gl.createBuffer();
                    _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
                    _gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );

                    // when using MRT, select the correct color buffer for the subsequent read command

                    if ( renderTarget.textures.length > 1 ) _gl.readBuffer( _gl.COLOR_ATTACHMENT0 + textureIndex );

                    _gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );

                    // reset the frame buffer to the currently set buffer before waiting
                    const currFramebuffer = _currentRenderTarget !== null ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;
                    state.bindFramebuffer( _gl.FRAMEBUFFER, currFramebuffer );

                    // check if the commands have finished every 8 ms
                    const sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );

                    _gl.flush();

                    await probeAsync( _gl, sync, 4 );

                    // read the data and delete the buffer
                    _gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );
                    _gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );
                    _gl.deleteBuffer( glBuffer );
                    _gl.deleteSync( sync );

                    return buffer;

                } else {

                    throw new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.' );

                }

            }

        };

        /**
         * Copies pixels from the current bound framebuffer into the given texture.
         *
         * @param {FramebufferTexture} texture - The texture.
         * @param {?Vector2} [position=null] - The start position of the copy operation.
         * @param {number} [level=0] - The mip level. The default represents the base mip.
         */
        this.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) {

            const levelScale = Math.pow( 2, - level );
            const width = Math.floor( texture.image.width * levelScale );
            const height = Math.floor( texture.image.height * levelScale );

            const x = position !== null ? position.x : 0;
            const y = position !== null ? position.y : 0;

            textures.setTexture2D( texture, 0 );

            _gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, x, y, width, height );

            state.unbindTexture();

        };

        const _srcFramebuffer = _gl.createFramebuffer();
        const _dstFramebuffer = _gl.createFramebuffer();

        /**
         * Copies data of the given source texture into a destination texture.
         *
         * When using render target textures as `srcTexture` and `dstTexture`, you must make sure both render targets are initialized
         * {@link WebGLRenderer#initRenderTarget}.
         *
         * @param {Texture} srcTexture - The source texture.
         * @param {Texture} dstTexture - The destination texture.
         * @param {?(Box2|Box3)} [srcRegion=null] - A bounding box which describes the source region. Can be two or three-dimensional.
         * @param {?(Vector2|Vector3)} [dstPosition=null] - A vector that represents the origin of the destination region. Can be two or three-dimensional.
         * @param {number} [srcLevel=0] - The source mipmap level to copy.
         * @param {?number} [dstLevel=null] - The destination mipmap level.
         */
        this.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, srcLevel = 0, dstLevel = null ) {

            // support the previous signature with just a single dst mipmap level
            if ( dstLevel === null ) {

                if ( srcLevel !== 0 ) {

                    // @deprecated, r171
                    warnOnce( 'WebGLRenderer: copyTextureToTexture function signature has changed to support src and dst mipmap levels.' );
                    dstLevel = srcLevel;
                    srcLevel = 0;

                } else {

                    dstLevel = 0;

                }

            }

            // gather the necessary dimensions to copy
            let width, height, depth, minX, minY, minZ;
            let dstX, dstY, dstZ;
            const image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ dstLevel ] : srcTexture.image;
            if ( srcRegion !== null ) {

                width = srcRegion.max.x - srcRegion.min.x;
                height = srcRegion.max.y - srcRegion.min.y;
                depth = srcRegion.isBox3 ? srcRegion.max.z - srcRegion.min.z : 1;
                minX = srcRegion.min.x;
                minY = srcRegion.min.y;
                minZ = srcRegion.isBox3 ? srcRegion.min.z : 0;

            } else {

                const levelScale = Math.pow( 2, - srcLevel );
                width = Math.floor( image.width * levelScale );
                height = Math.floor( image.height * levelScale );
                if ( srcTexture.isDataArrayTexture ) {

                    depth = image.depth;

                } else if ( srcTexture.isData3DTexture ) {

                    depth = Math.floor( image.depth * levelScale );

                } else {

                    depth = 1;

                }

                minX = 0;
                minY = 0;
                minZ = 0;

            }

            if ( dstPosition !== null ) {

                dstX = dstPosition.x;
                dstY = dstPosition.y;
                dstZ = dstPosition.z;

            } else {

                dstX = 0;
                dstY = 0;
                dstZ = 0;

            }

            // Set up the destination target
            const glFormat = utils.convert( dstTexture.format );
            const glType = utils.convert( dstTexture.type );
            let glTarget;

            if ( dstTexture.isData3DTexture ) {

                textures.setTexture3D( dstTexture, 0 );
                glTarget = _gl.TEXTURE_3D;

            } else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {

                textures.setTexture2DArray( dstTexture, 0 );
                glTarget = _gl.TEXTURE_2D_ARRAY;

            } else {

                textures.setTexture2D( dstTexture, 0 );
                glTarget = _gl.TEXTURE_2D;

            }

            _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 );

            // used for copying data from cpu
            const currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );
            const currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );
            const currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );
            const currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );
            const currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );

            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );
            _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );
            _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );
            _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );
            _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );

            // set up the src texture
            const isSrc3D = srcTexture.isDataArrayTexture || srcTexture.isData3DTexture;
            const isDst3D = dstTexture.isDataArrayTexture || dstTexture.isData3DTexture;
            if ( srcTexture.isDepthTexture ) {

                const srcTextureProperties = properties.get( srcTexture );
                const dstTextureProperties = properties.get( dstTexture );
                const srcRenderTargetProperties = properties.get( srcTextureProperties.__renderTarget );
                const dstRenderTargetProperties = properties.get( dstTextureProperties.__renderTarget );
                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, srcRenderTargetProperties.__webglFramebuffer );
                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, dstRenderTargetProperties.__webglFramebuffer );

                for ( let i = 0; i < depth; i ++ ) {

                    // if the source or destination are a 3d target then a layer needs to be bound
                    if ( isSrc3D ) {

                        _gl.framebufferTextureLayer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( srcTexture ).__webglTexture, srcLevel, minZ + i );
                        _gl.framebufferTextureLayer( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, properties.get( dstTexture ).__webglTexture, dstLevel, dstZ + i );

                    }

                    _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, _gl.DEPTH_BUFFER_BIT, _gl.NEAREST );

                }

                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );

            } else if ( srcLevel !== 0 || srcTexture.isRenderTargetTexture || properties.has( srcTexture ) ) {

                // get the appropriate frame buffers
                const srcTextureProperties = properties.get( srcTexture );
                const dstTextureProperties = properties.get( dstTexture );

                // bind the frame buffer targets
                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, _srcFramebuffer );
                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, _dstFramebuffer );

                for ( let i = 0; i < depth; i ++ ) {

                    // assign the correct layers and mip maps to the frame buffers
                    if ( isSrc3D ) {

                        _gl.framebufferTextureLayer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, srcTextureProperties.__webglTexture, srcLevel, minZ + i );

                    } else {

                        _gl.framebufferTexture2D( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, srcTextureProperties.__webglTexture, srcLevel );

                    }

                    if ( isDst3D ) {

                        _gl.framebufferTextureLayer( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, dstTextureProperties.__webglTexture, dstLevel, dstZ + i );

                    } else {

                        _gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, dstTextureProperties.__webglTexture, dstLevel );

                    }

                    // copy the data using the fastest function that can achieve the copy
                    if ( srcLevel !== 0 ) {

                        _gl.blitFramebuffer( minX, minY, width, height, dstX, dstY, width, height, _gl.COLOR_BUFFER_BIT, _gl.NEAREST );

                    } else if ( isDst3D ) {

                        _gl.copyTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ + i, minX, minY, width, height );

                    } else {

                        _gl.copyTexSubImage2D( glTarget, dstLevel, dstX, dstY, minX, minY, width, height );

                    }

                }

                // unbind read, draw buffers
                state.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );
                state.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );

            } else {

                if ( isDst3D ) {

                    // copy data into the 3d texture
                    if ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {

                        _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );

                    } else if ( dstTexture.isCompressedArrayTexture ) {

                        _gl.compressedTexSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );

                    } else {

                        _gl.texSubImage3D( glTarget, dstLevel, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );

                    }

                } else {

                    // copy data into the 2d texture
                    if ( srcTexture.isDataTexture ) {

                        _gl.texSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image.data );

                    } else if ( srcTexture.isCompressedTexture ) {

                        _gl.compressedTexSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, image.width, image.height, glFormat, image.data );

                    } else {

                        _gl.texSubImage2D( _gl.TEXTURE_2D, dstLevel, dstX, dstY, width, height, glFormat, glType, image );

                    }

                }

            }

            // reset values
            _gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );
            _gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );
            _gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );
            _gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );
            _gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );

            // Generate mipmaps only when copying level 0
            if ( dstLevel === 0 && dstTexture.generateMipmaps ) {

                _gl.generateMipmap( glTarget );

            }

            state.unbindTexture();

        };

        /**
         * Initializes the given WebGLRenderTarget memory. Useful for initializing a render target so data
         * can be copied into it using {@link WebGLRenderer#copyTextureToTexture} before it has been
         * rendered to.
         *
         * @param {WebGLRenderTarget} target - The render target.
         */
        this.initRenderTarget = function ( target ) {

            if ( properties.get( target ).__webglFramebuffer === undefined ) {

                textures.setupRenderTarget( target );

            }

        };

        /**
         * Initializes the given texture. Useful for preloading a texture rather than waiting until first
         * render (which can cause noticeable lags due to decode and GPU upload overhead).
         *
         * @param {Texture} texture - The texture.
         */
        this.initTexture = function ( texture ) {

            if ( texture.isCubeTexture ) {

                textures.setTextureCube( texture, 0 );

            } else if ( texture.isData3DTexture ) {

                textures.setTexture3D( texture, 0 );

            } else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {

                textures.setTexture2DArray( texture, 0 );

            } else {

                textures.setTexture2D( texture, 0 );

            }

            state.unbindTexture();

        };

        /**
         * Can be used to reset the internal WebGL state. This method is mostly
         * relevant for applications which share a single WebGL context across
         * multiple WebGL libraries.
         */
        this.resetState = function () {

            _currentActiveCubeFace = 0;
            _currentActiveMipmapLevel = 0;
            _currentRenderTarget = null;

            state.reset();
            bindingStates.reset();

        };

        if ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {

            __THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );

        }

    }

    /**
     * Defines the coordinate system of the renderer.
     *
     * In `WebGLRenderer`, the value is always `WebGLCoordinateSystem`.
     *
     * @type {WebGLCoordinateSystem|WebGPUCoordinateSystem}
     * @default WebGLCoordinateSystem
     * @readonly
     */
    get coordinateSystem() {

        return WebGLCoordinateSystem;

    }

    /**
     * Defines the output color space of the renderer.
     *
     * @type {SRGBColorSpace|LinearSRGBColorSpace}
     * @default SRGBColorSpace
     */
    get outputColorSpace() {

        return this._outputColorSpace;

    }

    set outputColorSpace( colorSpace ) {

        this._outputColorSpace = colorSpace;

        const gl = this.getContext();
        gl.drawingBufferColorSpace = ColorManagement._getDrawingBufferColorSpace( colorSpace );
        gl.unpackColorSpace = ColorManagement._getUnpackColorSpace();

    }

}